Skip to content
Components
@app-studio/components

Tabs

A versatile component for organizing and displaying content in separate, selectable sections.

View component source

Import

ts
import { Tabs } from '@app-studio/components';

New to the library? Complete installation and provider setup first.

Interactive examples

Try the component, then open Code to copy the complete example.

INTERACTIVE EXAMPLE

Loading preview…

Props

Required props are marked below. A dash indicates an unspecified default. Design system configuration can override implementation defaults.

Scroll horizontally to see every column.

Tabs
PropTypeDefaultDescription
tabsTab[]—Array of tab objects to be displayed. Each tab needs a unique `value`. (Data-driven approach)Source
defaultValuestring | number—Optional value of the tab to be active initially. Defaults to the first tab if not provided or not found.Source
onTabChange((activeTab: Tab) => void)—Optional callback function triggered when the active tab changes. Receives the newly active tab object.Source
viewsTabsStyles—Optional styles object to customize the appearance of the tabs container, headers, text, and content area.Source
variantTabsVariant
"pill""underline""segmented"
—Visual presentation style for the tab list.Source
iconPosition"bottom" | "left" | "right" | "top"
"bottom""left""right""top"
—Optional position of the icon relative to the text in tab headers.Source
renderTab((tab: Tab, isActive: boolean, onClick: () => void) => React.ReactNode)—Optional custom renderer for a single tab header. Receives the tab data, whether it's currently active, and an onClick handler to activate the tab.Source
renderContent((activeTab: Tab) => React.ReactNode)—Optional custom renderer for the content area. Receives the currently active tab object. If not provided, the `content` property from the active tab object will be rendered.Source
keepMountedboolean—By default only the ACTIVE tab's content is mounted — inactive tabs do not exist in the DOM (their state resets on switch, and tests must activate a tab before asserting on its content). Set `keepMounted` to mount every tab's content up front and toggle visibility with `display: none`, preserving internal state across switches. Only applies to the data-driven `tabs` path; `renderContent` still receives the active tab only.Source
valuestring | number—Current value for controlled compound component patternSource
onValueChange((value: string | number) => void)—Callback when tab value changes in compound component pattern. Receives the tab's value — matching `Tabs.type.ts` and `Tabs.state.ts`, which already declared `string | number` while this one said `any`.Source
children
View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null
—Children for compound component patternSource

Tabs.List

Scroll horizontally to see every column.

Tabs.List
PropTypeDefaultDescription
children Required
View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null
—Children (TabsTrigger components)Source
views{ container?: ViewProps; }—Custom styles for the list containerSource

Tabs.Trigger

Scroll horizontally to see every column.

Tabs.Trigger
PropTypeDefaultDescription
value Requiredstring—Unique value for this tabSource
children Required
View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null
—Children content for the triggerSource
disabledboolean—Whether this trigger is disabledSource
views{ trigger?: ViewProps; activeState?: ViewProps; }—Custom styles for the triggerSource

Tabs.Content

Scroll horizontally to see every column.

Tabs.Content
PropTypeDefaultDescription
value Requiredstring—Value that this content corresponds toSource
children Required
View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null
—Children content to display when this tab is activeSource
views{ content?: ViewProps; }—Custom styles for the contentSource

For shared layout, color, and responsive properties, read Styling & composition and Responsive layouts. Additional native element attributes depend on the target platform.

Usage guidance

  • Give controls a visible label or an accessible name, and verify keyboard interaction. See Accessibility.
  • For controlled inputs, update the value from the callback shown in the props table. Keep application state in your component or form library.
  • These previews run in the browser. Check React Native setup for platform requirements and differences.
Browse documentation source