Tabs may be used navigate between multiple URLs. Tabs are intended as page-level navigation - if you're looking at just switching panels of content, please use SegmentedControl.
Props
Usage guidelines
- To break up a large collection of content into logical, digestible views.
- To switch between different, yet related views, such as Updates and Messages.
- When any UI or content above the Tabs is altered upon selection. Use Link instead.
- To break up content that is not related to each other or is not on the same hierarchical level.
Best practices
Place Tabs directly above the target content.
Use Tabs as a way to filter content. Consider using SegmentedControl in this use-case.
Keep Tab labels concise, ideally one to two words.
Truncate labels in Tabs. If there is not enough horizontal space, allow the Tabs to scroll horizontally on mobile and touch surfaces. For desktop, wrap the group of tabs to multiple lines.
Order Tabs by relevance — the first tab should be the most logical starting view. Ideally, sequence Tabs by association — tabs with similar content should be adjacent to each other.
Disable or hide Tabs if a Tab's content is empty. There should always be at least 2 Tabs. We don't support applying a disabled state for the Tab as it can cause usability and accessibility issues.
Accessibility
Tabs are intended for page-level navigation between multiple URLs. Each tab must have an individual title that precisely describes the tab content. Provide a short, descriptive label for screen-readers using accessibilityLabel
. It is helpful for users of assistive technologies so they have the necessary information to navigate the content efficiently.
Keyboard
Tab key navigates the tabs.
Enter/return key activates a tab (i.e., it navigates to the link href
).
Screen Reader
The tab/link must announce a state of "current" if the href
matches the current window URL.
Localization
Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.
The Tab's title should be 3 words or less: long enough to be understood by users but short enough to prevent text wrapping. Aim for a single word when possible.
Variants
Wrapping
Wrapping to multiple lines is available for tight spaces on desktop interfaces where horizontal scrolling is harder and less accessible.
import { useState } from 'react'; import { Box, Flex, Label, Switch, Tabs, Text } from 'gestalt'; export default function Example() { const [activeIndex, setActiveIndex] = useState(0); const [wrap, setWrap] = useState(false); return ( <Flex alignItems="center" height="100%" justifyContent="center" width="100%" > <Flex alignItems="start" direction="column" gap={{ column: 4, row: 0 }}> <Flex gap={{ row: 4, column: 0 }}> <Label htmlFor="wrap"> <Text>Wrap</Text> </Label> <Switch id="wrap" onChange={() => setWrap(!wrap)} switched={wrap} /> </Flex> <Box borderStyle="sm" maxWidth={500} overflow="auto" padding={1}> <Tabs activeTabIndex={activeIndex} onChange={({ activeTabIndex, event }) => { event.preventDefault(); setActiveIndex(activeTabIndex); }} tabs={[ { href: 'https://pinterest.com', text: 'Boards for You' }, { href: 'https://pinterest.com', text: 'Pins for You' }, { href: 'https://pinterest.com', text: 'Following' }, { href: 'https://pinterest.com', text: 'People to Follow' }, ]} wrap={wrap} /> </Box> </Flex> </Flex> ); }
Indicator
Use the indicator
field on individual tabs to indicate notifications. You can either show a red dot or a number — numbers greater than 99 will be shown as "99+".
import { useState } from 'react'; import { Flex, Tabs } from 'gestalt'; export default function Example() { const [activeIndex, setActiveIndex] = useState(0); return ( <Flex alignItems="center" height="100%" justifyContent="center" width="100%" > <Tabs activeTabIndex={activeIndex} onChange={({ activeTabIndex, event }) => { event.preventDefault(); setActiveIndex(activeTabIndex); }} tabs={[ { href: 'https://pinterest.com', text: 'Boards for You' }, { href: 'https://pinterest.com', text: 'Pins for You', indicator: 'dot', }, { href: 'https://pinterest.com', text: 'Following', indicator: 3 }, { href: 'https://pinterest.com', text: 'People to Follow', indicator: 112, }, ]} wrap /> </Flex> ); }
Background color
import { useState } from 'react'; import { Box, Flex, Label, Switch, Tabs, Text } from 'gestalt'; export default function Example() { const [activeIndex, setActiveIndex] = useState(0); const [isTransparent, setIsTransparent] = useState(false); return ( <Flex alignItems="center" direction="column" gap={4} height="100%" justifyContent="center" width="100%" > <Flex gap={{ row: 4, column: 0 }}> <Label htmlFor="color"> <Text>Transparent background</Text> </Label> <Switch id="color" onChange={() => setIsTransparent((value) => !value)} switched={isTransparent} /> </Flex> <Box borderStyle="sm" color="secondary" paddingX={3} paddingY={1}> <Tabs activeTabIndex={activeIndex} bgColor={isTransparent ? 'transparent' : 'default'} onChange={({ activeTabIndex, event }) => { event.preventDefault(); setActiveIndex(activeTabIndex); }} tabs={[ { href: 'https://pinterest.com', text: 'Boards for You' }, { href: 'https://pinterest.com', text: 'Pins for You' }, { href: 'https://pinterest.com', text: 'Following' }, { href: 'https://pinterest.com', text: 'People to Follow' }, ]} wrap /> </Box> </Flex> ); }
Component quality checklist
Quality item | Status | Status description |
---|---|---|
Figma Library | Ready | Component is available in Figma for web and mobile web. |
Responsive Web | Ready | Component responds to changing viewport sizes in web and mobile web. |
Related
Link
Link is used to navigate to different areas of the product or to external sites. Link is the preferred component in cases where you want to direct the user to unrelated content.
SegmentedControl
SegmentedControl is used to switch between views within a small area of content, such as a
Popover. SegmentedControl is preferred when changing state or selection within a view.