Tabs
Tabs switch between views that sit at the same level of one screen. Primary tabs sit at the top of the content, secondary tabs divide what is inside one of those views.
Usage
Tabs provide a user interface for navigating between distinct sections or pages within an
application. Each <Tabs> component contains multiple <Tab> children, and the <Tabs> component itself can be styled as either primary or secondary
variants to suit different use cases.
Primary tabs
<script lang="ts">
import { Tab, Tabs } from 'noph-ui'
</script>
<Tabs value="videos">
<Tab badge badgeLabel="2" value="videos">Videos</Tab>
<Tab value="theme">Theme</Tab>
<Tab badge value="settings">Settings</Tab>
</Tabs>
Icons
<script lang="ts">
import { Tab, Tabs } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Tabs value="videos">
<Tab badge badgeLabel="2" value="videos">
{#snippet icon()}<Icon>videocam</Icon>{/snippet}Videos
</Tab>
<Tab value="theme">{#snippet icon()}<Icon>palette</Icon>{/snippet}Theme</Tab>
<Tab badge value="settings">{#snippet icon()}<Icon>settings</Icon>{/snippet}Settings</Tab>
</Tabs>
Secondary tabs
<script lang="ts">
import { Tab, Tabs } from 'noph-ui'
</script>
<Tabs variant="secondary" value="videos">
<Tab badge badgeLabel="2" value="videos">Videos</Tab>
<Tab value="theme">Theme</Tab>
<Tab badge value="settings">Settings</Tab>
</Tabs>
Icons
<script lang="ts">
import { Tab, Tabs } from 'noph-ui'
import { Icon } from 'noph-ui/icons'
</script>
<Tabs variant="secondary" value="videos">
<Tab badge badgeLabel="2" value="videos">
{#snippet icon()}<Icon>videocam</Icon>{/snippet}Videos
</Tab>
<Tab value="theme">{#snippet icon()}<Icon>palette</Icon>{/snippet}Theme</Tab>
<Tab badge value="settings">{#snippet icon()}<Icon>settings</Icon>{/snippet}Settings</Tab>
</Tabs>
Selection
The value prop on <Tabs> determines which tab is currently
selected. Each <Tab> must have a unique value within the same <Tabs> group. When the value of <Tabs> matches a <Tab>'s value, that tab is highlighted as selected. To react to
tab changes, use bind:value on <Tabs> to keep track of the selected
tab in your component state.
<script lang="ts">
import { Tab, Tabs } from 'noph-ui'
let value = $state('videos')
</script>
<div>
<Tabs bind:value>
<Tab value="videos">Videos</Tab>
<Tab value="theme">Theme</Tab>
<Tab value="settings">Settings</Tab>
</Tabs>
<div style="margin-top:1rem;font-size:0.825rem">Selected tab: {value}</div>
</div>
Links
To enable navigation between pages or routes, use the href attribute on <Tab>. This renders the tab as a link, allowing users to navigate to different
routes when a tab is clicked. The href attribute works seamlessly with the value prop, so you can track which tab is selected even when navigating between pages.
This approach is especially useful for SSR and deep linking.
<script lang="ts">
import { page } from '$app/state'
import { Tab, Tabs } from 'noph-ui'
</script>
<div>
<Tabs variant="secondary" value={page.url.searchParams.get('tab') || 'videos'}>
<Tab data-sveltekit-noscroll href="/components/tabs?tab=videos" value="videos">Videos</Tab>
<Tab data-sveltekit-noscroll href="/components/tabs?tab=theme" value="theme">Theme</Tab>
<Tab data-sveltekit-noscroll href="/components/tabs?tab=settings" value="settings">
Settings
</Tab>
</Tabs>
</div>
Theming
Tabs are drawn from the color roles: --np-color-primary for the indicator and the
selected label, --np-color-on-surface-variant for the rest, and --np-color-secondary for the focus ring.
| Custom property | Default value |
|---|---|
--np-tabs-indicator-radius | --np-shape-corner-full on primary tabs, 0 on secondary tabs |
Accessibility
The strip renders role="tablist" and each tab role="tab" with aria-selected. The tabs share one tab stop: the left and right arrow keys move
between them, Home and End jump to the ends, and Tab leaves the strip for the panel.
Where a tab reveals a panel on the same page, give the panel an id, point at it with controls and mark the panel role="tabpanel". Tabs that navigate take an href instead and stay real links. A badge on a tab needs badgeAriaLabel to say what the number counts.
API
Tabs
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
value | number | string | Value of the current tab. | |
variant | 'primary' | 'secondary' | 'primary' | Sets the visual style of the tab. Use 'primary' for the default appearance or 'secondary' for an alternative style. |
element | HTMLElement | A reference to the root DOM element of the component. |
Tab
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
inlineIcon | boolean | false | Only affects the primary variant. |
badge | boolean | false | |
badgeLabel | string | number | undefined | undefined | A string representing the label to be displayed inside a badge element. |
badgeAriaLabel | string | undefined | undefined | Announces the badge, for example "2 new videos". Without it the badge is aria-hidden and only the tab label is read out. |
controls | string | undefined | undefined | The id of the panel this tab controls, rendered as aria-controls. |
value | number | string | undefined | The value associated with this tab. Used to identify which tab is selected. |
icon | Snippet | undefined | undefined | Provides a custom icon for the tab, typically rendered before the tab label. Accepts a
Svelte snippet, such as an <Icon> component. |
href | string | undefined | When set, the tab will render as a link using the provided URL. This allows navigation to other pages or routes when the tab is clicked. |
element | HTMLElement | A reference to the root DOM element of the component. |