Tabs

Tablist primitive that synchronizes tab focus, selection, and panel visibility.

Default horizontal

With orientation omitted, Tabs arranges its tablist horizontally.

A live component preview.
Semantic HTML.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<ui-tabs
  label="View"
>
  <section
    id="preview"
    aria-label="Preview"
  >A live component preview.</section>
  <section
    id="code"
    aria-label="Code"
  >Semantic HTML.</section>
</ui-tabs>
<script setup>
  import { UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiTabs
    label="View"
  >
    <section
      id="preview"
      aria-label="Preview"
    >A live component preview.</section>
    <section
      id="code"
      aria-label="Code"
    >Semantic HTML.</section>
  </UiTabs>
</template>
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="View"
  >
    <section
      id="preview"
      aria-label="Preview"
    >A live component preview.</section>
    <section
      id="code"
      aria-label="Code"
    >Semantic HTML.</section>
  </UiTabs>;
}
/** @jsxImportSource preact */
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="View"
  >
    <section
      id="preview"
      aria-label="Preview"
    >A live component preview.</section>
    <section
      id="code"
      aria-label="Code"
    >Semantic HTML.</section>
  </UiTabs>;
}
<script>
  import { UiTabs } from "@threadlabs/looma";
</script>

<UiTabs
  label="View"
>
  <section
    id="preview"
    aria-label="Preview"
  >A live component preview.</section>
  <section
    id="code"
    aria-label="Code"
  >Semantic HTML.</section>
</UiTabs>
import { Component } from "@angular/core";
import { UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs],
  template: `
    <div
      ui-tabs
      [label]="'View'"
    >
      <section
        id="preview"
        aria-label="Preview"
      >A live component preview.</section>
      <section
        id="code"
        aria-label="Code"
      >Semantic HTML.</section>
    </div>
  `,
})
export default class Example {}

stretch

Stretch shares the tab list's full width equally between tabs; by default each tab is only as wide as its label.

Billed every month.
Billed once a year.
One payment.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<ui-tabs
  label="Plan"
  stretch
>
  <section
    id="monthly"
    aria-label="Monthly"
  >Billed every month.</section>
  <section
    id="yearly"
    aria-label="Yearly"
  >Billed once a year.</section>
  <section
    id="lifetime"
    aria-label="Lifetime"
  >One payment.</section>
</ui-tabs>
<script setup>
  import { UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiTabs
    label="Plan"
    :stretch="true"
  >
    <section
      id="monthly"
      aria-label="Monthly"
    >Billed every month.</section>
    <section
      id="yearly"
      aria-label="Yearly"
    >Billed once a year.</section>
    <section
      id="lifetime"
      aria-label="Lifetime"
    >One payment.</section>
  </UiTabs>
</template>
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Plan"
    stretch
  >
    <section
      id="monthly"
      aria-label="Monthly"
    >Billed every month.</section>
    <section
      id="yearly"
      aria-label="Yearly"
    >Billed once a year.</section>
    <section
      id="lifetime"
      aria-label="Lifetime"
    >One payment.</section>
  </UiTabs>;
}
/** @jsxImportSource preact */
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Plan"
    stretch
  >
    <section
      id="monthly"
      aria-label="Monthly"
    >Billed every month.</section>
    <section
      id="yearly"
      aria-label="Yearly"
    >Billed once a year.</section>
    <section
      id="lifetime"
      aria-label="Lifetime"
    >One payment.</section>
  </UiTabs>;
}
<script>
  import { UiTabs } from "@threadlabs/looma";
</script>

<UiTabs
  label="Plan"
  stretch
>
  <section
    id="monthly"
    aria-label="Monthly"
  >Billed every month.</section>
  <section
    id="yearly"
    aria-label="Yearly"
  >Billed once a year.</section>
  <section
    id="lifetime"
    aria-label="Lifetime"
  >One payment.</section>
</UiTabs>
import { Component } from "@angular/core";
import { UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs],
  template: `
    <div
      ui-tabs
      [label]="'Plan'"
      [stretch]="true"
    >
      <section
        id="monthly"
        aria-label="Monthly"
      >Billed every month.</section>
      <section
        id="yearly"
        aria-label="Yearly"
      >Billed once a year.</section>
      <section
        id="lifetime"
        aria-label="Lifetime"
      >One payment.</section>
    </div>
  `,
})
export default class Example {}

Overflow on narrow screens

When the tabs do not fit, the tab list scrolls sideways (swipe on touch screens) while the tab area stays full width.

Overview
Activity
Members
Integrations
Billing
Settings

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<div
  style="max-width: 18rem"
>
  <ui-tabs
    label="Project"
  >
    <section
      id="overview"
      aria-label="Overview"
    >Overview</section>
    <section
      id="activity"
      aria-label="Activity"
    >Activity</section>
    <section
      id="members"
      aria-label="Members"
    >Members</section>
    <section
      id="integrations"
      aria-label="Integrations"
    >Integrations</section>
    <section
      id="billing"
      aria-label="Billing"
    >Billing</section>
    <section
      id="settings-tab"
      aria-label="Settings"
    >Settings</section>
  </ui-tabs>
</div>
<script setup>
  import { UiTabs } from "@threadlabs/looma";
</script>

<template>
  <div
    style="max-width: 18rem"
  >
    <UiTabs
      label="Project"
    >
      <section
        id="overview"
        aria-label="Overview"
      >Overview</section>
      <section
        id="activity"
        aria-label="Activity"
      >Activity</section>
      <section
        id="members"
        aria-label="Members"
      >Members</section>
      <section
        id="integrations"
        aria-label="Integrations"
      >Integrations</section>
      <section
        id="billing"
        aria-label="Billing"
      >Billing</section>
      <section
        id="settings-tab"
        aria-label="Settings"
      >Settings</section>
    </UiTabs>
  </div>
</template>
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <div
    style={{"maxWidth":"18rem"}}
  >
    <UiTabs
      label="Project"
    >
      <section
        id="overview"
        aria-label="Overview"
      >Overview</section>
      <section
        id="activity"
        aria-label="Activity"
      >Activity</section>
      <section
        id="members"
        aria-label="Members"
      >Members</section>
      <section
        id="integrations"
        aria-label="Integrations"
      >Integrations</section>
      <section
        id="billing"
        aria-label="Billing"
      >Billing</section>
      <section
        id="settings-tab"
        aria-label="Settings"
      >Settings</section>
    </UiTabs>
  </div>;
}
/** @jsxImportSource preact */
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <div
    style={{"maxWidth":"18rem"}}
  >
    <UiTabs
      label="Project"
    >
      <section
        id="overview"
        aria-label="Overview"
      >Overview</section>
      <section
        id="activity"
        aria-label="Activity"
      >Activity</section>
      <section
        id="members"
        aria-label="Members"
      >Members</section>
      <section
        id="integrations"
        aria-label="Integrations"
      >Integrations</section>
      <section
        id="billing"
        aria-label="Billing"
      >Billing</section>
      <section
        id="settings-tab"
        aria-label="Settings"
      >Settings</section>
    </UiTabs>
  </div>;
}
<script>
  import { UiTabs } from "@threadlabs/looma";
</script>

<div
  style="max-width: 18rem"
>
  <UiTabs
    label="Project"
  >
    <section
      id="overview"
      aria-label="Overview"
    >Overview</section>
    <section
      id="activity"
      aria-label="Activity"
    >Activity</section>
    <section
      id="members"
      aria-label="Members"
    >Members</section>
    <section
      id="integrations"
      aria-label="Integrations"
    >Integrations</section>
    <section
      id="billing"
      aria-label="Billing"
    >Billing</section>
    <section
      id="settings-tab"
      aria-label="Settings"
    >Settings</section>
  </UiTabs>
</div>
import { Component } from "@angular/core";
import { UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs],
  template: `
    <div
      style="max-width: 18rem"
    >
      <div
        ui-tabs
        [label]="'Project'"
      >
        <section
          id="overview"
          aria-label="Overview"
        >Overview</section>
        <section
          id="activity"
          aria-label="Activity"
        >Activity</section>
        <section
          id="members"
          aria-label="Members"
        >Members</section>
        <section
          id="integrations"
          aria-label="Integrations"
        >Integrations</section>
        <section
          id="billing"
          aria-label="Billing"
        >Billing</section>
        <section
          id="settings-tab"
          aria-label="Settings"
        >Settings</section>
      </div>
    </div>
  `,
})
export default class Example {}

orientation="vertical"

Vertical orientation changes the tablist axis while preserving the same tab and panel relationships.

Profile settings
Security settings

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<ui-tabs
  label="Settings"
  orientation="vertical"
  value="profile"
>
  <section
    id="profile"
    aria-label="Profile"
  >Profile settings</section>
  <section
    id="security"
    aria-label="Security"
  >Security settings</section>
</ui-tabs>
<script setup>
  import { UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiTabs
    label="Settings"
    orientation="vertical"
    value="profile"
  >
    <section
      id="profile"
      aria-label="Profile"
    >Profile settings</section>
    <section
      id="security"
      aria-label="Security"
    >Security settings</section>
  </UiTabs>
</template>
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Settings"
    orientation="vertical"
    value="profile"
  >
    <section
      id="profile"
      aria-label="Profile"
    >Profile settings</section>
    <section
      id="security"
      aria-label="Security"
    >Security settings</section>
  </UiTabs>;
}
/** @jsxImportSource preact */
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Settings"
    orientation="vertical"
    value="profile"
  >
    <section
      id="profile"
      aria-label="Profile"
    >Profile settings</section>
    <section
      id="security"
      aria-label="Security"
    >Security settings</section>
  </UiTabs>;
}
<script>
  import { UiTabs } from "@threadlabs/looma";
</script>

<UiTabs
  label="Settings"
  orientation="vertical"
  value="profile"
>
  <section
    id="profile"
    aria-label="Profile"
  >Profile settings</section>
  <section
    id="security"
    aria-label="Security"
  >Security settings</section>
</UiTabs>
import { Component } from "@angular/core";
import { UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs],
  template: `
    <div
      ui-tabs
      [label]="'Settings'"
      [orientation]="'vertical'"
      [value]="'profile'"
    >
      <section
        id="profile"
        aria-label="Profile"
      >Profile settings</section>
      <section
        id="security"
        aria-label="Security"
      >Security settings</section>
    </div>
  `,
})
export default class Example {}

Manual activation

Arrow keys browse tab labels without loading another panel; Enter or Space selects the focused tab.

Summary report.
Detail report.
History report.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<ui-tabs
  label="Reports"
  activation="manual"
>
  <section
    id="summary-report"
    aria-label="Summary"
  >Summary report.</section>
  <section
    id="detail-report"
    aria-label="Detail"
  >Detail report.</section>
  <section
    id="history-report"
    aria-label="History"
  >History report.</section>
</ui-tabs>
<script setup>
  import { UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiTabs
    label="Reports"
    activation="manual"
  >
    <section
      id="summary-report"
      aria-label="Summary"
    >Summary report.</section>
    <section
      id="detail-report"
      aria-label="Detail"
    >Detail report.</section>
    <section
      id="history-report"
      aria-label="History"
    >History report.</section>
  </UiTabs>
</template>
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Reports"
    activation="manual"
  >
    <section
      id="summary-report"
      aria-label="Summary"
    >Summary report.</section>
    <section
      id="detail-report"
      aria-label="Detail"
    >Detail report.</section>
    <section
      id="history-report"
      aria-label="History"
    >History report.</section>
  </UiTabs>;
}
/** @jsxImportSource preact */
import { UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Reports"
    activation="manual"
  >
    <section
      id="summary-report"
      aria-label="Summary"
    >Summary report.</section>
    <section
      id="detail-report"
      aria-label="Detail"
    >Detail report.</section>
    <section
      id="history-report"
      aria-label="History"
    >History report.</section>
  </UiTabs>;
}
<script>
  import { UiTabs } from "@threadlabs/looma";
</script>

<UiTabs
  label="Reports"
  activation="manual"
>
  <section
    id="summary-report"
    aria-label="Summary"
  >Summary report.</section>
  <section
    id="detail-report"
    aria-label="Detail"
  >Detail report.</section>
  <section
    id="history-report"
    aria-label="History"
  >History report.</section>
</UiTabs>
import { Component } from "@angular/core";
import { UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs],
  template: `
    <div
      ui-tabs
      [label]="'Reports'"
      [activation]="'manual'"
    >
      <section
        id="summary-report"
        aria-label="Summary"
      >Summary report.</section>
      <section
        id="detail-report"
        aria-label="Detail"
      >Detail report.</section>
      <section
        id="history-report"
        aria-label="History"
      >History report.</section>
    </div>
  `,
})
export default class Example {}

Rich tab labels

Author tab buttons in the tab slot when labels need icons or counts; each button value matches a panel id.

Unread and recent items.
Older items.

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-icon/ui-icon.html"
>

<ui-tabs
  label="Workspace views"
>
  <button
    slot="tab"
    value="inbox-view"
  > <ui-icon
      name="folder"
    ></ui-icon> Inbox <span>(3)</span> </button>
  <button
    slot="tab"
    value="archive-view"
  >Archive</button>
  <section
    id="inbox-view"
    aria-label="Inbox"
  >Unread and recent items.</section>
  <section
    id="archive-view"
    aria-label="Archive"
  >Older items.</section>
</ui-tabs>
<script setup>
  import { UiIcon, UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiTabs
    label="Workspace views"
  >
    <template #tab>
      <button
        value="inbox-view"
      > <UiIcon
          name="folder"
        /> Inbox <span>(3)</span> </button><button
        value="archive-view"
      >Archive</button>
    </template>
    <section
      id="inbox-view"
      aria-label="Inbox"
    >Unread and recent items.</section>
    <section
      id="archive-view"
      aria-label="Archive"
    >Older items.</section>
  </UiTabs>
</template>
import { UiIcon, UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Workspace views"
    slots={{
      tab: <><button
        value="inbox-view"
      >{" "}<UiIcon
          name="folder"
        /> Inbox <span>(3)</span>{" "}</button><button
        value="archive-view"
      >Archive</button></>,
    }}
  >
    <section
      id="inbox-view"
      aria-label="Inbox"
    >Unread and recent items.</section>
    <section
      id="archive-view"
      aria-label="Archive"
    >Older items.</section>
  </UiTabs>;
}
/** @jsxImportSource preact */
import { UiIcon, UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiTabs
    label="Workspace views"
    slots={{
      tab: <><button
        value="inbox-view"
      >{" "}<UiIcon
          name="folder"
        /> Inbox <span>(3)</span>{" "}</button><button
        value="archive-view"
      >Archive</button></>,
    }}
  >
    <section
      id="inbox-view"
      aria-label="Inbox"
    >Unread and recent items.</section>
    <section
      id="archive-view"
      aria-label="Archive"
    >Older items.</section>
  </UiTabs>;
}
<script>
  import { UiIcon, UiTabs } from "@threadlabs/looma";
</script>

{#snippet tab()}
  <button
    value="inbox-view"
  > <UiIcon
      name="folder"
    /> Inbox <span>(3)</span> </button><button
    value="archive-view"
  >Archive</button>
{/snippet}

<UiTabs
  label="Workspace views"
  slots={{ tab }}
>
  <section
    id="inbox-view"
    aria-label="Inbox"
  >Unread and recent items.</section>
  <section
    id="archive-view"
    aria-label="Archive"
  >Older items.</section>
</UiTabs>
import { Component } from "@angular/core";
import { UiIcon, UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiTabs, UiIcon],
  template: `
    <div
      ui-tabs
      [label]="'Workspace views'"
    >
      <ng-container ngProjectAs="[slot='tab']">
        <button
          value="inbox-view"
        > <span
            ui-icon
            name="folder"
          ></span> Inbox <span>(3)</span> </button><button
          value="archive-view"
        >Archive</button>
      </ng-container>
      <section
        id="inbox-view"
        aria-label="Inbox"
      >Unread and recent items.</section>
      <section
        id="archive-view"
        aria-label="Archive"
      >Older items.</section>
    </div>
  `,
})
export default class Example {}

Synced group

Tabs in the same group select the same label together, and remember the choice for the next visit.

pnpm add @threadlabs/looma
npm install @threadlabs/looma
pnpm dev
npm run dev

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-tabs/ui-tabs.html"
>

<ui-stack
  gap="s"
>
  <ui-tabs
    label="Install"
    group="package-manager"
  >
    <section
      id="install-pnpm"
      aria-label="pnpm"
    ><code>pnpm add @threadlabs/looma</code></section>
    <section
      id="install-npm"
      aria-label="npm"
    ><code>npm install @threadlabs/looma</code></section>
  </ui-tabs>
  <ui-tabs
    label="Run"
    group="package-manager"
  >
    <section
      id="run-pnpm"
      aria-label="pnpm"
    ><code>pnpm dev</code></section>
    <section
      id="run-npm"
      aria-label="npm"
    ><code>npm run dev</code></section>
  </ui-tabs>
</ui-stack>
<script setup>
  import { UiStack, UiTabs } from "@threadlabs/looma";
</script>

<template>
  <UiStack
    gap="s"
  >
    <UiTabs
      label="Install"
      group="package-manager"
    >
      <section
        id="install-pnpm"
        aria-label="pnpm"
      ><code>pnpm add @threadlabs/looma</code></section>
      <section
        id="install-npm"
        aria-label="npm"
      ><code>npm install @threadlabs/looma</code></section>
    </UiTabs>
    <UiTabs
      label="Run"
      group="package-manager"
    >
      <section
        id="run-pnpm"
        aria-label="pnpm"
      ><code>pnpm dev</code></section>
      <section
        id="run-npm"
        aria-label="npm"
      ><code>npm run dev</code></section>
    </UiTabs>
  </UiStack>
</template>
import { UiStack, UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiTabs
      label="Install"
      group="package-manager"
    >
      <section
        id="install-pnpm"
        aria-label="pnpm"
      ><code>pnpm add @threadlabs/looma</code></section>
      <section
        id="install-npm"
        aria-label="npm"
      ><code>npm install @threadlabs/looma</code></section>
    </UiTabs>
    <UiTabs
      label="Run"
      group="package-manager"
    >
      <section
        id="run-pnpm"
        aria-label="pnpm"
      ><code>pnpm dev</code></section>
      <section
        id="run-npm"
        aria-label="npm"
      ><code>npm run dev</code></section>
    </UiTabs>
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiStack, UiTabs } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="s"
  >
    <UiTabs
      label="Install"
      group="package-manager"
    >
      <section
        id="install-pnpm"
        aria-label="pnpm"
      ><code>pnpm add @threadlabs/looma</code></section>
      <section
        id="install-npm"
        aria-label="npm"
      ><code>npm install @threadlabs/looma</code></section>
    </UiTabs>
    <UiTabs
      label="Run"
      group="package-manager"
    >
      <section
        id="run-pnpm"
        aria-label="pnpm"
      ><code>pnpm dev</code></section>
      <section
        id="run-npm"
        aria-label="npm"
      ><code>npm run dev</code></section>
    </UiTabs>
  </UiStack>;
}
<script>
  import { UiStack, UiTabs } from "@threadlabs/looma";
</script>

<UiStack
  gap="s"
>
  <UiTabs
    label="Install"
    group="package-manager"
  >
    <section
      id="install-pnpm"
      aria-label="pnpm"
    ><code>pnpm add @threadlabs/looma</code></section>
    <section
      id="install-npm"
      aria-label="npm"
    ><code>npm install @threadlabs/looma</code></section>
  </UiTabs>
  <UiTabs
    label="Run"
    group="package-manager"
  >
    <section
      id="run-pnpm"
      aria-label="pnpm"
    ><code>pnpm dev</code></section>
    <section
      id="run-npm"
      aria-label="npm"
    ><code>npm run dev</code></section>
  </UiTabs>
</UiStack>
import { Component } from "@angular/core";
import { UiStack, UiTabs } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack, UiTabs],
  template: `
    <div
      ui-stack
      [gap]="'s'"
    >
      <div
        ui-tabs
        [label]="'Install'"
        [group]="'package-manager'"
      >
        <section
          id="install-pnpm"
          aria-label="pnpm"
        ><code>pnpm add &#64;threadlabs/looma</code></section>
        <section
          id="install-npm"
          aria-label="npm"
        ><code>npm install &#64;threadlabs/looma</code></section>
      </div>
      <div
        ui-tabs
        [label]="'Run'"
        [group]="'package-manager'"
      >
        <section
          id="run-pnpm"
          aria-label="pnpm"
        ><code>pnpm dev</code></section>
        <section
          id="run-npm"
          aria-label="npm"
        ><code>npm run dev</code></section>
      </div>
    </div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: div

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
activationIn auto mode, arrow keys move focus and select the next panel. In manual mode, arrows move focus while Enter or Space selects a panel. Use manual when displaying a panel takes time.activationkeywordautoauto, manual
densityCompact trades padding and type size for rows that fit more on screen.densitykeywordcomfortablecomfortable, compact
groupTabs with the same nonempty group share one selection: choosing a tab selects the tab with the same data-value (or label when no value is authored) in every other Tabs of that group in the document, and the choice is remembered for the next visit. Use it for alternatives a reader picks once, such as a package manager or language.groupstring—
labelThe tab list's accessible name, announced when focus enters the list. Name what the tabs switch between.labelstringTabs—
orientationhorizontal puts the tabs in a row above the panels, moved between with the Left and Right arrow keys; vertical puts them in a column beside the panels, moved between with Up and Down.orientationkeywordhorizontalhorizontal, vertical
stretchShare the full width of the tab list equally between tabs instead of sizing each to its label.stretchbooleanfalse—
valueThe id or authored data-value of the selected panel, initially or when set externally; empty selects the first panel. Choosing a tab updates it from there and reports a select event. A panel without an id is given a generated one.valuestring—

Framework props

NameTypeDefaultAllowed values
activation"auto" | "manual"autoauto, manual
density"comfortable" | "compact"comfortablecomfortable, compact
groupstring—
labelstringTabs—
orientation"horizontal" | "vertical"horizontalhorizontal, vertical
stretchbooleanfalse—
valuestring—

Events

NameDetailDescription
selectobject
  • value: string (required)
  • previousValue: string (required)
  • trigger: keyword (required)
Emitted when a selectable option becomes active.

Slots

NamePurpose
tabNamed content for the tab region.
defaultDefault child content.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

TokenDeclared valuesFallback
--ui-tabs-panel-padding—var(--ui-space-4)
--ui-tabs-tab-min-block-sizevar(--ui-control-size) | var(--ui-control-size-sm)—
--ui-tabs-tab-padding-blockvar(--ui-space-2) | var(--ui-space-1)—
--ui-tabs-tab-padding-inlinevar(--ui-space-3) | var(--ui-space-2)—

Shared tokens

TokenFallback
--ui-accent-line-width—
--ui-accent-subtle—
--ui-accent-subtle-text—
--ui-border-divider—
--ui-border-width—
--ui-control-size—
--ui-control-size-sm—
--ui-focus-ring—
--ui-focus-width—
--ui-font-medium—
--ui-font-size-sm—
--ui-motion-ease—
--ui-motion-fast—
--ui-radius-sm—
--ui-space-1—
--ui-space-2—
--ui-space-3—
--ui-space-4—
--ui-surface-muted—
--ui-text-primary—
--ui-text-secondary—