Underline Tabs Underline Tabs are best used when switching between related content within a page.
< State initial = { 0 } >
{ ( [ active , setActive ] ) => (
< TabGroup >
< Tab onClick = { ( ) => setActive ( 0 ) } active = { active === 0 } > All </ Tab >
< Tab onClick = { ( ) => setActive ( 1 ) } active = { active === 1 } > Action Required </ Tab >
< Tab onClick = { ( ) => setActive ( 2 ) } active = { active === 2 } > Insights </ Tab >
< Tab onClick = { ( ) => setActive ( 3 ) } active = { active === 3 } > Settings </ Tab >
</ TabGroup >
) }
</ State >
Underline tabs have a minimum width of 48px. The text and hover/active underline are always equal in width beyond this minimum.
With Badges < TabGroup >
< Tab > Ready To Bill < Tag compact badge > 127 </ Tag > </ Tab >
< Tab active > Action Required < Tag compact badge color = " critical " > 25 </ Tag > </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
With Icons < TabGroup >
< Tab active > < Icon name = " info " /> Action Requested </ Tab >
< Tab > < Icon name = " poll " /> Insights </ Tab >
< Tab > < Icon name = " settings " /> Settings </ Tab >
</ TabGroup >
Tab Action Tab actions, represented with a button or icon, can be represented as a tab itself. This can be useful for non-navigational actions related to the tab content such as adding a new tab.
< TabGroup
action = {
< Button size = " xsmall " primary > Call to Action </ Button >
}
>
< style > {`
.icon-hov {
cursor: pointer;
}
.icon-hov:hover svg { fill: #2270ee; }
`} </ style >
< Tab active > Action Requested </ Tab >
< Tab > Insights </ Tab >
</ TabGroup >
< TabGroup
action = {
< Icon name = " add_circle " className = " icon-hov fs-4 c-neutral-200 " />
}
>
< style > {`
.icon-hov {
cursor: pointer;
}
.icon-hov:hover svg { fill: #2270ee; }
`} </ style >
< Tab active > Action Requested </ Tab >
< Tab > Insights </ Tab >
</ TabGroup >
Divided Tabs A vertical pipe (|
) divider can be applied to both sides of an inactive tab. This is useful when there are many tabs on a page.
< State initial = { 0 } >
{ ( [ active , setActive ] ) => (
< TabGroup
verticallyDivided
action = {
< Button size = " xsmall " primary > Call to Action </ Button >
}
>
< Tab active = { active == 0 } onClick = { ( ) => setActive ( 0 ) } > All </ Tab >
< Tab active = { active == 1 } onClick = { ( ) => setActive ( 1 ) } > Action Required </ Tab >
< Tab active = { active == 2 } onClick = { ( ) => setActive ( 2 ) } > Insights </ Tab >
< Tab active = { active == 3 } onClick = { ( ) => setActive ( 3 ) } > Action Required </ Tab >
< Tab active = { active == 4 } onClick = { ( ) => setActive ( 4 ) } > Insights </ Tab >
< Tab active = { active == 5 } onClick = { ( ) => setActive ( 5 ) } > Action Required </ Tab >
</ TabGroup >
) }
</ State >
Fitted < Card >
< Card.Section >
< TabGroup fitted divider = { false } >
< Tab active > < Icon name = " info " /> Action Requested </ Tab >
< Tab > < Icon name = " poll " /> Insights </ Tab >
< Tab > < Icon name = " settings " /> Settings </ Tab >
</ TabGroup >
</ Card.Section >
< Card.Section >
This card has supporting text below as a natural lead-in to additional content.
</ Card.Section >
</ Card >
Underline tabs can be fitted to a card. This pattern should only be used when there are 2 or 3 tabs.
Index Tabs Index Tabs are best used when switching between tabs only affects content within the visual container its attached to. They can also be nested within an underline tab.
< TabGroup type = " index " >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
Index tabs have a minimum width of 64px. The text and hover/active underline are always equal in width beyond this minimum.
With Badges < TabGroup type = " index " >
< Tab > Ready To Bill < Tag compact badge > 127 </ Tag > </ Tab >
< Tab active > Action Required < Tag compact badge color = " critical " > 25 </ Tag > </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
With Icons < TabGroup type = " index " >
< Tab active > < Icon name = " info " /> Action Requested </ Tab >
< Tab > < Icon name = " poll " /> Insights </ Tab >
< Tab > < Icon name = " settings " /> Settings </ Tab >
</ TabGroup >
Fitted < Card padding = " thin " >
< Card.Section >
< TabGroup type = " index " fitted divider = { false } >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab active > Settings </ Tab >
</ TabGroup >
</ Card.Section >
< Card.Section >
Lorem ipsum dolar emit
</ Card.Section >
</ Card >
Max Width Prevents a tab from exceeding 240px
in length. When combined with the fitted property, can make tabs stretch to the maximum width.
< TabGroup type = " index " fitted maxWidth >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
</ TabGroup >
Left Aligned Tab Text By default, text is centered within a tab.
< TabGroup type = " index " fitted maxWidth textAlign = " left " >
< Tab active > John Doe </ Tab >
< Tab > New Tab </ Tab >
< Tab > Insights </ Tab >
</ TabGroup >
Divided Tabs < State initial = { 0 } >
{ ( [ active , setActive ] ) => (
< TabGroup
type = " index "
verticallyDivided
action = {
< Button size = " xsmall " primary > Call to Action </ Button >
}
>
< Tab active = { active == 0 } onClick = { ( ) => setActive ( 0 ) } > All </ Tab >
< Tab active = { active == 1 } onClick = { ( ) => setActive ( 1 ) } > Action Required </ Tab >
< Tab active = { active == 2 } onClick = { ( ) => setActive ( 2 ) } > Insights </ Tab >
< Tab active = { active == 3 } onClick = { ( ) => setActive ( 3 ) } > Action Required </ Tab >
< Tab active = { active == 4 } onClick = { ( ) => setActive ( 4 ) } > Insights </ Tab >
< Tab active = { active == 5 } onClick = { ( ) => setActive ( 5 ) } > Action Required </ Tab >
</ TabGroup >
) }
</ State >
With a Background Tabs can take advantage of different background colors. The blue active state and dividers are removed, and inactive tabs switch text color.
< div className = ' box-demo ' >
< TabGroup type = " index " dark divider = { false } >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
< style > {`
.box-demo {
background: #8C9CA5;
padding: 20px 20px 0;
}
.tab-demo {
background: white;
width: calc(100% + 40px);
height: 40px;
margin: 0 -20px;
}
`} </ style >
< div className = ' tab-demo ' />
</ div >
< div className = ' box-demo-2 ' >
< TabGroup type = " index " dark verticallyDivided divider = { false } >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
< style > {`
.box-demo-2 {
background: #232323;
padding: 20px 20px 0;
}
.tab-demo {
background: white;
width: calc(100% + 40px);
height: 40px;
margin: 0 -20px;
}
`} </ style >
< div className = ' tab-demo ' />
</ div >
Sizing A taller variation of index tabs can be used for important navigation at the top of a page.
< TabGroup type = " index " size = " large " >
< Tab active > Customers </ Tab >
< Tab > Available Inventory </ Tab >
< Tab > Analytics </ Tab >
< Tab > Marketing </ Tab >
</ TabGroup >
Nested If a page needs multiple levels of tabs, the index tab can be nested in a underline tab.
< div >
< TabGroup >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
</ TabGroup >
< br />
< Card padding = " thin " >
< Card.Section >
< TabGroup type = " index " divider = { false } >
< Tab > SubTab 1 </ Tab >
< Tab > SubTab 2 </ Tab >
< Tab active > SubTab 3 </ Tab >
< Tab > SubTab 4 </ Tab >
< Tab > SubTab 5 </ Tab >
</ TabGroup >
</ Card.Section >
< Card.Section >
Lorem ipsum dolar emit
</ Card.Section >
</ Card >
</ div >
Responsive Tabs will scroll horizontally when overflowed.
< div >
< Headline className = " m-b-3 " > Horizontal scrolling </ Headline >
< TabGroup >
< Tab active > All </ Tab >
< Tab > Action Required </ Tab >
< Tab > Insights </ Tab >
< Tab > Settings </ Tab >
< Tab > More Items </ Tab >
< Tab > Sixth Item </ Tab >
</ TabGroup >
< br />
< Card padding = " thin " >
< Card.Section >
< TabGroup type = " index " divider = { false } >
< Tab > SubTab 1 </ Tab >
< Tab active > SubTab 2 </ Tab >
< Tab > SubTab 3 </ Tab >
< Tab > SubTab 4 </ Tab >
< Tab > SubTab 5 </ Tab >
< Tab > SubTab 6 </ Tab >
</ TabGroup >
</ Card.Section >
< Card.Section >
Lorem ipsum dolar emit
</ Card.Section >
</ Card >
</ div >
Best Practices Avoid tab names over 2 words long. Should be used with 2–10 choices. Only 1 tab should be active at a time. Avoid the disabled state. If a user cannot use it, remove it from the tab. Content within a tab should be mutually exclusive from another tab's content. A visual divider should always be present. The default divider is a gray line. On tab switch, the <title>
should change to reflect the new content. More UX practices: Tabs, Used Right (NN Group) Importing import { TabGroup , Tab } from '@servicetitan/design-system' ;