A set of layered sections of content—known as tab panels—that are displayed one at a time.
import React from 'react';
import { styled } from '@stitches/react';
import { violet, mauve, blackA, green } from '@radix-ui/colors';
import * as TabsPrimitive from '@radix-ui/react-tabs';
const StyledTabs = styled(TabsPrimitive.Root, {
display: 'flex',
flexDirection: 'column',
width: 300,
boxShadow: `0 2px 10px ${blackA.blackA4}`,
});
const StyledList = styled(TabsPrimitive.List, {
flexShrink: 0,
display: 'flex',
borderBottom: `1px solid ${mauve.mauve6}`,
});
const StyledTrigger = styled(TabsPrimitive.Trigger, {
all: 'unset',
fontFamily: 'inherit',
backgroundColor: 'white',
padding: '0 20px',
height: 45,
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 15,
lineHeight: 1,
color: mauve.mauve11,
userSelect: 'none',
'&:first-child': { borderTopLeftRadius: 6 },
'&:last-child': { borderTopRightRadius: 6 },
'&:hover': { color: violet.violet11 },
'&[data-state="active"]': {
color: violet.violet11,
boxShadow: 'inset 0 -1px 0 0 currentColor, 0 1px 0 0 currentColor',
},
'&:focus': { position: 'relative', boxShadow: `0 0 0 2px black` },
});
const StyledContent = styled(TabsPrimitive.Content, {
flexGrow: 1,
padding: 20,
backgroundColor: 'white',
borderBottomLeftRadius: 6,
borderBottomRightRadius: 6,
outline: 'none',
'&:focus': { boxShadow: `0 0 0 2px black` },
});
// Exports
export const Tabs = StyledTabs;
export const TabsList = StyledList;
export const TabsTrigger = StyledTrigger;
export const TabsContent = StyledContent;
// Your app...
const Box = styled('div', {});
const Flex = styled('div', { display: 'flex' });
const Text = styled('div', {
marginBottom: 20,
color: mauve.mauve11,
fontSize: 15,
lineHeight: 1.5,
});
const Button = styled('button', {
all: 'unset',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
padding: '0 15px',
fontSize: 15,
lineHeight: 1,
fontWeight: 500,
height: 35,
variants: {
variant: {
violet: {
backgroundColor: 'white',
color: violet.violet11,
boxShadow: `0 2px 10px ${blackA.blackA7}`,
'&:hover': { backgroundColor: mauve.mauve3 },
'&:focus': { boxShadow: `0 0 0 2px black` },
},
green: {
backgroundColor: green.green4,
color: green.green11,
'&:hover': { backgroundColor: green.green5 },
'&:focus': { boxShadow: `0 0 0 2px ${green.green7}` },
},
},
},
defaultVariants: {
variant: 'violet',
},
});
const Fieldset = styled('fieldset', {
all: 'unset',
marginBottom: 15,
width: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
});
const Label = styled('label', {
fontSize: 13,
lineHeight: 1,
marginBottom: 10,
color: violet.violet12,
display: 'block',
});
const Input = styled('input', {
all: 'unset',
flex: '1 0 auto',
borderRadius: 4,
padding: '0 10px',
fontSize: 15,
lineHeight: 1,
color: violet.violet11,
boxShadow: `0 0 0 1px ${violet.violet7}`,
height: 35,
'&:focus': { boxShadow: `0 0 0 2px ${violet.violet8}` },
});
const TabsDemo = () => (
<Box css={{}}>
<Tabs defaultValue="tab1">
<TabsList aria-label="Manage your account">
<TabsTrigger value="tab1">Account</TabsTrigger>
<TabsTrigger value="tab2">Password</TabsTrigger>
</TabsList>
<TabsContent value="tab1">
<Text>Make changes to your account here. Click save when you're done.</Text>
<Fieldset>
<Label htmlFor="name">Name</Label>
<Input id="name" defaultValue="Pedro Duarte" />
</Fieldset>
<Fieldset>
<Label htmlFor="username">Username</Label>
<Input id="username" defaultValue="@peduarte" />
</Fieldset>
<Flex css={{ marginTop: 20, justifyContent: 'flex-end' }}>
<Button variant="green">Save changes</Button>
</Flex>
</TabsContent>
<TabsContent value="tab2">
<Text>Change your password here. After saving, you'll be logged out.</Text>
<Fieldset>
<Label htmlFor="currentPassword">Current password</Label>
<Input id="currentPassword" type="password" />
</Fieldset>
<Fieldset>
<Label htmlFor="newPassword">New password</Label>
<Input id="newPassword" type="password" />
</Fieldset>
<Fieldset>
<Label htmlFor="confirmPassword">Confirm password</Label>
<Input id="confirmPassword" type="password" />
</Fieldset>
<Flex css={{ marginTop: 20, justifyContent: 'flex-end' }}>
<Button variant="green">Change password</Button>
</Flex>
</TabsContent>
</Tabs>
</Box>
);
export default TabsDemo;
Install the component from your command line.
npm install @radix-ui/react-tabs
Import all parts and piece them together.
import * as Tabs from '@radix-ui/react-tabs';
export default () => (
<Tabs.Root>
<Tabs.List>
<Tabs.Trigger />
</Tabs.List>
<Tabs.Content />
</Tabs.Root>
);
Contains all the tabs component parts.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
defaultValue | string | |
value | string | |
onValueChange | function | |
orientation | enum | "horizontal" |
dir | enum | |
activationMode | enum | "automatic" |
Data Attribute | Values |
---|---|
[data-orientation] | "vertical" | "horizontal" |
Contains the triggers that are aligned along the edge of the active content.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
loop | boolean | true |
Data Attribute | Values |
---|---|
[data-orientation] | "vertical" | "horizontal" |
The button that activates its associated content.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
value* | string | |
disabled | boolean | false |
Data Attribute | Values |
---|---|
[data-state] | "active" | "inactive" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Contains the content associated with each trigger.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
value* | string | |
forceMount | boolean |
Data Attribute | Values |
---|---|
[data-state] | "active" | "inactive" |
[data-orientation] | "vertical" | "horizontal" |
You can create vertical tabs by using the orientation
prop.
import * as Tabs from '@radix-ui/react-tabs';
export default () => (
<Tabs.Root defaultValue="tab1" orientation="vertical">
<Tabs.List aria-label="tabs example">
<Tabs.Trigger value="tab1">One</Tabs.Trigger>
<Tabs.Trigger value="tab2">Two</Tabs.Trigger>
<Tabs.Trigger value="tab3">Three</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Tab one content</Tabs.Content>
<Tabs.Content value="tab2">Tab two content</Tabs.Content>
<Tabs.Content value="tab3">Tab three content</Tabs.Content>
</Tabs.Root>
);
Adheres to the Tabs WAI-ARIA design pattern.
Key | Description |
---|---|
Tab | When focus moves onto the tabs, focuses the active trigger. When a trigger is focused, moves focus to the active content. |
ArrowDown | Moves focus to the next trigger depending on orientation and activates its associated content. |
ArrowRight | Moves focus to the next trigger depending on orientation and activates its associated content. |
ArrowUp | Moves focus to the previous trigger depending on orientation and activates its associated content. |
ArrowLeft | Moves focus to the previous trigger depending on orientation and activates its associated content. |
Home | Moves focus to the first trigger and activates its associated content. |
End | Moves focus to the last trigger and activates its associated content. |