ds deployment.Tabs
Summary
Alternative contents, one shown at a time.
Usage
<Tabs defaultValue="react">
<TabsList>
<TabsTrigger value="react">React</TabsTrigger>
<TabsTrigger value="vue">Vue</TabsTrigger>
<TabsTrigger value="svelte">Svelte</TabsTrigger>
</TabsList>
<TabsContent value="react">
| Aspect | React |
| --- | --- |
| Type | Library |
| Templates | JSX |
| Reactivity | Re-render on state change |
</TabsContent>
<TabsContent value="vue">
| Aspect | Vue |
| --- | --- |
| Type | Framework |
| Templates | Single-file components with HTML templates |
| Reactivity | Reactive proxies |
</TabsContent>
<TabsContent value="svelte">
| Aspect | Svelte |
| --- | --- |
| Type | Compiler |
| Templates | `.svelte` files |
| Reactivity | Compiled at build time |
</TabsContent>
</Tabs>
result:
Same API as shadcn Tabs.
defaultValue is required (otherwise no tab is shown until hydration).
Markdown inside a TabsContent (a table, a code block, a list) needs a blank line after the opening tag and before the closing one.
Rich triggers
Triggers accept any markup:
<Tabs defaultValue="react">
<TabsList>
<TabsTrigger value="react">React <Badge>19</Badge></TabsTrigger>
<TabsTrigger value="vue">Vue</TabsTrigger>
</TabsList>
<TabsContent value="react">
| Aspect | React |
| --- | --- |
| Version | 19 |
| Released | December 2024 |
</TabsContent>
<TabsContent value="vue">
| Aspect | Vue |
| --- | --- |
| Version | 3 |
| Released | September 2020 |
</TabsContent>
</Tabs>
result:
Synced tabs
Tabs of the same syncKey switch together: picking a tab in one picks it in every other, on this page and on the others. The pick is remembered (in localStorage), after a reload and in other browser tabs.
<Tabs defaultValue="react" syncKey="framework">
<TabsList>
<TabsTrigger value="react">React</TabsTrigger>
<TabsTrigger value="vue">Vue</TabsTrigger>
<TabsTrigger value="svelte">Svelte</TabsTrigger>
</TabsList>
<TabsContent value="react">
Templates are JSX: markup in JavaScript.
</TabsContent>
<TabsContent value="vue">
Templates are HTML, in single-file components.
</TabsContent>
<TabsContent value="svelte">
Templates are HTML, in `.svelte` files.
</TabsContent>
</Tabs>
<Tabs defaultValue="react" syncKey="framework">
<TabsList>
<TabsTrigger value="react">React</TabsTrigger>
<TabsTrigger value="svelte">Svelte</TabsTrigger>
</TabsList>
<TabsContent value="react">
State changes re-render the component.
</TabsContent>
<TabsContent value="svelte">
State changes are compiled into DOM updates.
</TabsContent>
</Tabs>
result:
Templates are JSX: markup in JavaScript.
Templates are HTML, in single-file components.
Templates are HTML, in .svelte files.
State changes re-render the component.
State changes are compiled into DOM updates.
A Tabs without the picked tab stays as it is: pick Svelte above, then Vue, and the second one stays on Svelte. The pick is still Vue, for the next Tabs that has it. A page loaded with a pick none of its tabs have shows their defaultValue.
The page's HTML shows defaultValue: the picked tab replaces it once the page's JavaScript runs. A link to a #hash in a hidden panel opens its tab as a click would, so it picks that tab too.