Skip to content

CdsTabs

Tabs split the screen into sections of equal weight and switch between them in place, without going to another page. The bar is built from CdsTab components or from an items array, and the content of the sections is switched by CdsTabsView and CdsTabsViewItem.

Storybook GitLab Figma
Test coverage: 0% — low coverage
API in specs
0 / 107 props, events, slots and exposed members with a test
Test cases
5 unit · 0 browser
Code coverage
68.3% lines · 54.5% branches measured in v4.0.0-alpha.13
A11y (axe)
8 recommendations in 19 stories measured in v4.0.0-alpha.11

For a sequential process with steps and progress, use CdsSteps; to pick a single value in a form, use CdsButtonToggle.

Anatomy ​

Tabs consist of a bar and a content area: with tabs from items the content area is rendered automatically, with manual markup CdsTabsView is composed next to the bar. The bar is a container with tab buttons; the selected tab is highlighted by a moving slider.

Variations ​

Tabs and content ​

Sections are declared with CdsTab components in the default slot, and the content with CdsTabsViewItem components inside CdsTabsView. The value props bind a tab to its content, and a shared v-model keeps the bar and the content area in sync.

Tabs from an array ​

Pass an array of strings or { text, value } objects into items — the tabs and the content area are rendered automatically. The content of a section comes from the item.{value} slots, the label of a tab from the tab.{value} slots.

Alignment ​

The align prop pushes the tabs to the start of the bar (the default), to the center or to the end.

Layout ​

The grow prop stretches the tabs across the whole width of the bar — every tab takes an equal share of the free space.

The fixed-tabs prop also equalizes the width of the tabs, but caps it at 300px and centers the group.

The direction="vertical" prop turns the bar into a column — handy for settings and sections with a long list. The content area is placed next to it with a regular flex row.

Icons ​

A tab accepts the same content props as a button: prepend-icon and append-icon add an icon next to the text, icon leaves only the icon. For an icon tab do not forget aria-label — without text it stays the only name of the section.

The stacked prop puts the icon above the text — the tab becomes taller and more noticeable. Such a layout works well with align="center" in mobile scenarios.

States ​

The disabled prop turns a tab off, loading shows a loading indicator instead of the content.

Colors ​

Tabs accept the color aliases of the palette (neutral, red, green, cyan, purple…) or any CSS color. The color prop paints the text of the tabs, active-color the slider of the selected tab, bg-color the background of the whole bar, and base-color the background of the unselected tabs.

Scrolling ​

When the tabs do not fit into the bar, it scrolls. The show-arrows prop adds scroll arrows, center-active keeps the selected tab in the center of the bar.

Slider ​

The slider-transition prop picks the animation of the slider under the selected tab: shift (the default) moves it to the new tab, grow grows it in place, fade fades it in. The duration is set through slider-transition-duration, and hide-slider removes the slider entirely.

Slots ​

Slots replace the automatic rendering from items when you need your own markup:

SlotDescription
defaultYour own CdsTab when items is not set
tab, tab.{value}Tab for an items element: shared and for a specific value
item, item.{value}Section content: shared and for a specific value
viewExtra content inside CdsTabsView
prev, nextYour own scroll arrows

The tab and item slots receive the array element and replace the whole component — return CdsTab and CdsTabsViewItem with your own value from them. The tab.{value} and item.{value} slots replace the content only.

Guidelines ​

Scenarios ​

Card sections ​

Classic tabs: a product card with sections and a shared v-model. The review counter is a CdsBadge with the inline prop right inside the tab slot.

List filter ​

Tabs work without a content area too: v-model holds the selected status and the list is filtered by it through a computed. There is a single content area — only the selection changes.

Lazy loading of sections ​

A heavy section loads on the first open: a watch on v-model fires the request, CdsSkeletonLoader stands in for the content while it loads, and the already loaded sections open instantly.

Sections in a "More" menu ​

When there are more sections than fit into the bar, the rare ones hide into a CdsMenu whose activator is a regular "More" tab in the same bar. A click on "More" immediately shows the first section from the menu, the selected item takes the place of the first visible tab (the displaced one moves into the menu), and if the menu is closed without a choice, the bar and the content return to the current section.

API ​

CdsTabs ​

Props

NameTypeDefaultDescription
activeColorstring | undefined—Color of the component in its active state
align"title" | "start" | "end" | "center" | undefined'start'Alignment of the tabs inside the bar
baseColorstring | undefined—Color of the component in its inactive state
bgColorstring | undefined—Background color of the component
centerActiveboolean | undefined—Forces the active component to be aligned to the center.
colorstring | undefined—Component color
contentClassany—Adds classes to the slide group container
contentStyleany—Adds inline styles to the slide group container
direction"horizontal" | "vertical" | undefined'horizontal'Switches the component between horizontal and vertical layout.
disabledboolean | null | undefinednullDisabled state
fixedTabsboolean | undefined—Makes all tabs the same width regardless of the length of their labels
growboolean | undefined—Stretches the tabs across the whole available width of the container
heightstring | number | undefined—Height of the tab bar. A number is in pixels, a string takes any CSS unit
hideSliderboolean | undefined—Hides the underline indicator of the active tab
insetboolean | undefined—Styling with a background: the active tab is highlighted with a filled pill instead of an underline
insetPaddingstring | number | undefined—Padding of the background in inset mode. A number is in pixels, a string takes any CSS unit
insetRadiusstring | number | undefined—Corner radius of the background in inset mode. A number is in pixels, a string takes any CSS unit
itemsreadonly TabItem[] | undefined[]List of tabs. A string or a number is a label, an object is a tab with arbitrary CdsTab props
mandatoryboolean | "force" | undefined'force'Requires at least one item to stay selected
maxnumber | undefined—Maximum number of items that can be selected
mobileboolean | null | undefinednullDetermines the display mode of the component: true renders it in mobile mode, false in desktop mode, null makes the mode depend on the current breakpoint.
mobileBreakpointnumber | "xs" | "sm" | "md" | "lg" | "xl" | undefined—Sets the breakpoint at which the component switches to mobile mode. Accepts a number (for example, 600) or the name of a predefined breakpoint (xs, sm, md, lg, xl).
modelValueany—Value of the selected items of the group
multipleboolean | undefined—Allows selecting several items at once
nextIconIconValue | undefined'chevron-right'Icon for the “next” button.
prevIconIconValue | undefined'chevron-left'Icon for the “previous” button.
requiredboolean | "force" | undefined'force'Requires at least one item to stay selected
scrollToActiveboolean | undefinedtrueWhen true, the container scrolls the active component into view whenever it changes.
selectedClassstring | undefined'cds-tabs--selected'CSS class applied in the selected state
showArrowsstring | boolean | undefined—Changes how the arrows are shown. By default the arrows appear on desktop devices when the container overflows and stay hidden on mobile devices. true also shows them on mobile on overflow, desktop always shows them on desktop, mobile always on mobile, always on both, and never disables the arrows.
sliderTransition"shift" | "grow" | "fade" | undefined—Animation of the underline indicator of the active tab
sliderTransitionDurationstring | number | undefined—Duration of the indicator animation in milliseconds. 0 disables the flight; by default it follows the motion scale
spaced"both" | "start" | "end" | undefined—Pushes the prepend and append slots apart to the edges of the button.
stackedboolean | undefined—Lays out the icon and the label of the tab vertically — the icon above the text
tagstring | JSXComponent<any> | undefined'div'Custom HTML tag or component to render
textColorstring | undefined—Text color of the component

Events

NameTypeDescription
update:modelValue[value: unknown]Fires when the tab is switched. Passes the value of the new active tab

Slots

NameTypeDescription
defaultanyTabs and content when they are declared by hand instead of the items prop
itemCdsTabsSlot<any>Template for the tab content. The slot props carry the element from items
nextanyButton that scrolls the tab bar forward
prevanyButton that scrolls the tab bar backward
tabCdsTabsSlot<any>Template for the tab label. The slot props carry the element from items
viewanyThe whole tab content area — replaces the automatic CdsTabsView

CdsTab ​

Props

NameTypeDefaultDescription
activeColorstring | undefined—Color of the component in its active state
appearancedeprecated"inverse" | "primary" | "secondary" | "tertiary" | "transparent" | undefined—Visual appearance of the component. Deprecated: use variant and color
appendIconIconValue | undefined—Icon in the append slot, after the content
baseColorstring | undefined—Color of the component in its inactive state
blockboolean | undefined—Stretches the button to the full width of its container
color(string & {}) | "neutral" | "brand" | "accent" | "danger" | "inverse" | undefined'brand'Component color: a role, a palette alias, a theme token or a CSS color
contentstring | number | undefined—Content displayed in the component.
direction"horizontal" | "vertical" | undefined'horizontal'Switches the component between horizontal and vertical layout.
disabledboolean | null | undefinednullDisabled state
exactboolean | undefined—If true, the active state applies only on an exact route match
fixedboolean | undefined—Fixes the width of the tab so it does not stretch to the length of its label
heightstring | number | undefined—Component height
hideSliderboolean | undefined—Hides the underline indicator of the active tab
hrefstring | undefined—The href attribute of the link. When set, the component behaves as a regular link
iconboolean | IconValue | undefined—Icon to display; the component renders as an icon-only button
loadingstring | boolean | undefined—Loading indicator for the component
maxHeightstring | number | undefined—Maximum component height
maxWidthstring | number | undefined—Maximum component width
minHeightstring | number | undefined—Minimum component height
minWidthstring | number | undefined—Minimum component width
prependIconIconValue | undefined—Icon in the prepend slot, before the content
readonlyboolean | null | undefinednullRead-only state
replaceboolean | undefined—If true, navigation replaces the current history entry instead of pushing a new one
selectedClassstring | undefined'cds-tab--selected'CSS class applied in the selected state
sizenumber | "xs" | "sm" | "md" | "lg" | "xl" | undefined'md'Size of the component
sliderTransition"shift" | "grow" | "fade" | undefined—Animation of the underline indicator of the active tab
sliderTransitionDurationstring | number | undefined—Duration of the indicator animation in milliseconds. 0 disables the flight; by default it follows the motion scale
spaced"both" | "start" | "end" | undefined—Pushes the prepend and append slots apart to the edges of the button.
stackedboolean | undefined—Stacks the icon above the text instead of placing them side by side
tagstring | JSXComponent<any> | undefined'button'Custom HTML tag or component to render
textstring | number | undefined—Text displayed in the component.
themestring | undefined—Component theme
toLinkTo | undefined—Target route or route location object for RouterLink. When set, the component behaves as a RouterLink
valueany—Value of the component within the group
variant"solid" | "soft" | "outline" | "surface" | "ghost" | undefined'solid'Component variant: solid, soft, outline, surface, ghost
widthstring | number | undefined—Component width

Slots

NameTypeDescription
appendanyContent after the text
defaultanyContent inside the button
loaderanyLoading indicator
prependanyContent before the text

CdsTabsView ​

Props

NameTypeDefaultDescription
crossfadeboolean | undefined—Slides change with a smooth crossfade instead of a shift
direction"horizontal" | "vertical" | undefined'horizontal'Switches the component between horizontal and vertical layout.
disabledboolean | null | undefinednullDisabled state
maxnumber | undefined—Maximum number of items that can be selected
modelValueany—Value of the selected items of the group
multipleboolean | undefined—Allows selecting several items at once
reverseboolean | undefined—Inverts the direction of the transition animation between slides
selectedClassstring | undefined—CSS class applied in the selected state
tagstring | JSXComponent<any> | undefined'div'Custom HTML tag or component to render
themestring | undefined—Component theme
transitionDurationnumber | undefined—Duration of the transition animation between slides, in milliseconds
verticalArrowsboolean | "left" | "right" | undefined—Places the navigation arrows vertically: 'left' or 'right' — the side, true — the default side

Events

NameTypeDescription
update:modelValue[value: any]Fires when the shown content changes. Passes the value of the new active tab

Slots

NameTypeDescription
additional{ group: GroupProvide; }Extra content above the slides — indicator dots or your own navigation, for example
default{ group: GroupProvide; }Slides. The slot props carry the group state for controlling the active slide
next{ props: ControlProps; }Button that moves to the next slide. The slot props are ready to bind to your own button
prev{ props: ControlProps; }Button that moves to the previous slide. The slot props are ready to bind to your own button

CdsTabsViewItem ​

Props

NameTypeDefaultDescription
disabledboolean | null | undefinednullDisabled state
eagerboolean | undefined—Renders the content of the component right away. Useful when you have content that is not in the DOM but has to be indexed for SEO.
reverseTransitionstring | boolean | undefined—Transition used when the slide appears in the reverse direction. A transition component name, or false to turn the animation off
selectedClassstring | undefined—CSS class applied in the selected state
transitionstring | boolean | undefined—Transition used when the slide appears in the forward direction. A transition component name, or false to turn the animation off
valueany—Value of the component within the group

Slots

NameTypeDescription
defaultanyContent of the slide