❄ SnowballSH Foundation UI

Tabs

One recipe, two bindings — rendered side by side from the same source the package ships.

React

The write panel. Arrow keys move between tabs.

tabs.demo.tsx
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>
  );
}

Svelte

The write panel. Arrow keys move between tabs.

tabs.demo.svelte
<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>