Tabs
Pick a framework. Both use the same recipe, so the styling matches exactly.
The write panel. Arrow keys move between tabs.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { value: string; label: string }[] | One entry per tab. | |
| value | string | The active tab. In Svelte it is bindable with bind:value. | |
| onValueChange | (value: string) => void | Called when the active tab changes. | |
| children | content | Panel content for the active tab. |
Also takes className and children. Anything else passes through to the div.
import { useState } from "react";
import { Tabs } from "../react/index.js";
const items = [
{ value: "write", label: "Write" },
{ value: "preview", label: "Preview" },
{ value: "publish", label: "Publish" },
];
export default function TabsDemo() {
const [value, setValue] = useState("write");
return (
<Tabs items={items} value={value} onValueChange={setValue}>
<p className="text-ink-secondary">
The <span className="font-medium text-ink">{value}</span> panel. Arrow
keys move between tabs.
</p>
</Tabs>
);
}
The write panel. Arrow keys move between tabs.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { value: string; label: string }[] | One entry per tab. | |
| value | string | The active tab. In Svelte it is bindable with bind:value. | |
| onValueChange | (value: string) => void | Called when the active tab changes. | |
| children | content | Panel content for the active tab. |
Also takes class and snippet children. Anything else passes through to the div.
<script lang="ts">
import { Tabs } from "../svelte/index.js";
const items = [
{ value: "write", label: "Write" },
{ value: "preview", label: "Preview" },
{ value: "publish", label: "Publish" },
];
let value = $state("write");
</script>
<Tabs {items} bind:value>
<p class="text-ink-secondary">
The <span class="font-medium text-ink">{value}</span> panel. Arrow keys move between
tabs.
</p>
</Tabs>