Tabs# Component <neo-tabs> is a tabbed interface: clicking a <neo-tab> commits its value to the host, which reveals the matching <neo-tabpanel>. Arrow keys move focus across tabs; activation is manual (Enter or Space commits). Set auto-activate to opt into the selection-follows-focus pattern.
The preview routes through the in-browser server simulator. Its current Settings (network latency, a non-200 response, or an unreachable server) are in effect, so the live preview can look like it is misbehaving. Adjust them in the Settings panel.
Overview
Activity
Reports
Settings
Overview
A snapshot of the project — open issues, recent commits, and the CI status.
Activity
The chronological feed.
Reports
(unreachable in this demo)
Settings
Project-wide preferences.
HTML CSS
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
<neo-tabs data-signals="{tabs_value: 'overview'}" data-attr:value="$tabs_value" easing="280ms cubic-bezier(0.25, 1, 0.5, 1)" enter-animation="neo-tab-slide" exit-animation="neo-tab-slide">
<neo-tablist aria-label="Project">
<neo-tab value="overview">Overview</neo-tab>
<neo-tab value="activity">Activity</neo-tab>
<neo-tab value="reports" disabled>Reports</neo-tab>
<neo-tab value="settings">Settings</neo-tab>
</neo-tablist>
<neo-tabpanel value="overview">
<h3>Overview</h3>
<p>A snapshot of the project — open issues, recent commits, and the CI status.</p>
</neo-tabpanel>
<neo-tabpanel value="activity">
<h3>Activity</h3>
<p>The chronological feed.</p>
</neo-tabpanel>
<neo-tabpanel value="reports">
<h3>Reports</h3>
<p>(unreachable in this demo)</p>
</neo-tabpanel>
<neo-tabpanel value="settings">
<h3>Settings</h3>
<p>Project-wide preferences.</p>
</neo-tabpanel>
</neo-tabs> <neo-tabs value="inbox" easing="220ms ease">
<neo-tablist aria-label="Mailbox section">
<neo-tab value="inbox" aria-selected="true" tabindex="0">
<neo-icon name="mail"></neo-icon>
<span>Inbox</span>
</neo-tab>
<neo-tab value="messages" aria-selected="false" tabindex="-1">
<neo-icon name="message-square"></neo-icon>
<span>Messages</span>
</neo-tab>
<neo-tab value="notifications" aria-selected="false" tabindex="-1">
<neo-icon name="bell"></neo-icon>
<span>Notifications</span>
</neo-tab>
<neo-tab value="trash" disabled aria-selected="false" tabindex="-1">
<neo-icon name="trash-2"></neo-icon>
<span>Trash</span>
</neo-tab>
</neo-tablist>
<neo-tabpanel value="inbox">
<h3>Inbox</h3>
<p>Your incoming mail, threaded by sender.</p>
</neo-tabpanel>
<neo-tabpanel value="messages" hidden>
<h3>Messages</h3>
<p>Direct messages and chat threads.</p>
</neo-tabpanel>
<neo-tabpanel value="notifications" hidden>
<h3>Notifications</h3>
<p>Per-channel toggles for email, push, and digest.</p>
</neo-tabpanel>
<neo-tabpanel value="trash" hidden>
<h3>Trash</h3>
<p>(unreachable in this demo)</p>
</neo-tabpanel>
</neo-tabs> <neo-tabs value="overview">
<neo-tablist aria-label="Project (no animation)">
<neo-tab value="overview" aria-selected="true" tabindex="0">Overview</neo-tab>
<neo-tab value="activity" aria-selected="false" tabindex="-1">Activity</neo-tab>
<neo-tab value="reports" aria-selected="false" tabindex="-1">Reports</neo-tab>
</neo-tablist>
<neo-tabpanel value="overview">
<h3>Overview</h3>
<p>A snapshot of the project: open issues, recent commits, and the CI status.</p>
</neo-tabpanel>
<neo-tabpanel value="activity" hidden>
<h3>Activity</h3>
<p>The chronological feed.</p>
</neo-tabpanel>
<neo-tabpanel value="reports" hidden>
<h3>Reports</h3>
<p>Aggregated reports by week / month / quarter.</p>
</neo-tabpanel>
</neo-tabs> <neo-tabs
value="general"
easing="1s cubic-bezier(0.32, 0.72, 0, 1)"
enter-animation="tabs-tilt"
exit-animation="tabs-tilt"
>
<neo-tablist aria-label="Preferences (zoom)">
<neo-tab value="general" aria-selected="true" tabindex="0">General</neo-tab>
<neo-tab value="appearance" aria-selected="false" tabindex="-1">Appearance</neo-tab>
<neo-tab value="advanced" aria-selected="false" tabindex="-1">Advanced</neo-tab>
</neo-tablist>
<neo-tabpanel value="general">
<h3>General</h3>
<p>Display name, timezone, language.</p>
</neo-tabpanel>
<neo-tabpanel value="appearance" hidden>
<h3>Appearance</h3>
<p>Theme, density, accent color.</p>
</neo-tabpanel>
<neo-tabpanel value="advanced" hidden>
<h3>Advanced</h3>
<p>Feature flags and developer options.</p>
</neo-tabpanel>
</neo-tabs> <div class="tabs-underline-pg">
<neo-tabs value="overview" easing="180ms ease">
<neo-tablist aria-label="Repository">
<neo-tab value="overview" aria-selected="true" tabindex="0">Overview</neo-tab>
<neo-tab value="issues" aria-selected="false" tabindex="-1">Issues</neo-tab>
<neo-tab value="pulls" aria-selected="false" tabindex="-1">Pull requests</neo-tab>
<neo-tab value="actions" aria-selected="false" tabindex="-1">Actions</neo-tab>
</neo-tablist>
<neo-tabpanel value="overview">
<p>README, recent commits, and the CI badge.</p>
</neo-tabpanel>
<neo-tabpanel value="issues" hidden>
<p>The open and closed issue tracker.</p>
</neo-tabpanel>
<neo-tabpanel value="pulls" hidden>
<p>Pending and merged pull requests.</p>
</neo-tabpanel>
<neo-tabpanel value="actions" hidden>
<p>Workflow runs and scheduled jobs.</p>
</neo-tabpanel>
</neo-tabs>
</div> .tabs-underline-pg {
--neo-tabs-list-bg: transparent;
--neo-tabs-list-padding: 0;
--neo-tabs-radius: 0;
--neo-tabs-tab-active-bg: transparent;
--neo-tabs-tab-active-shadow: none;
--neo-tabs-tab-padding-y: 0.6rem;
--neo-tabs-tab-padding-x: 1rem;
}
.tabs-underline-pg neo-tablist {
width: 100%;
border-bottom: 1px solid var(--btn-border, currentColor);
gap: 0.25rem;
}
.tabs-underline-pg neo-tab {
border-radius: 0;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 120ms ease, border-color 120ms ease;
}
.tabs-underline-pg neo-tab[aria-selected="true"] {
border-bottom-color: var(--accent, currentColor);
}
<neo-tabs value="day" auto-activate>
<neo-tablist aria-label="Time range">
<neo-tab value="day" aria-selected="true" tabindex="0">Day</neo-tab>
<neo-tab value="week" aria-selected="false" tabindex="-1">Week</neo-tab>
<neo-tab value="month" aria-selected="false" tabindex="-1">Month</neo-tab>
<neo-tab value="year" aria-selected="false" tabindex="-1">Year</neo-tab>
</neo-tablist>
<neo-tabpanel value="day">
<p>Activity over the last 24 hours.</p>
</neo-tabpanel>
<neo-tabpanel value="week" hidden>
<p>Activity over the last 7 days.</p>
</neo-tabpanel>
<neo-tabpanel value="month" hidden>
<p>Activity over the last 30 days.</p>
</neo-tabpanel>
<neo-tabpanel value="year" hidden>
<p>Activity over the last 365 days.</p>
</neo-tabpanel>
</neo-tabs> <neo-tabs value="general" orientation="vertical">
<neo-tablist aria-label="Preferences">
<neo-tab value="general" aria-selected="true" tabindex="0">General</neo-tab>
<neo-tab value="appearance" aria-selected="false" tabindex="-1">Appearance</neo-tab>
<neo-tab value="advanced" aria-selected="false" tabindex="-1">Advanced</neo-tab>
</neo-tablist>
<neo-tabpanel value="general">
<h3>General</h3>
<p>Display name, timezone, language.</p>
</neo-tabpanel>
<neo-tabpanel value="appearance" hidden>
<h3>Appearance</h3>
<p>Theme, density, accent color.</p>
</neo-tabpanel>
<neo-tabpanel value="advanced" hidden>
<h3>Advanced</h3>
<p>Feature flags and developer options.</p>
</neo-tabpanel>
</neo-tabs> Reference# Attributes # Name Type Default Description valuestring reflected observednone Active tab value. orientation"horizontal" | "vertical" observedhorizontalLayout axis. auto-activatebooleanfalseArrow keys commit the selection in addition to moving focus. easingstring observednone CSS transition shorthand for the panel swap. enter-animationstring observednone @keyframes name for the entering panel.exit-animationstring observednone @keyframes name for the exiting panel.
States # Name Description :state(forward)Set on <neo-tabs> when the new tab sits after the previous one; the built-in and author animations branch on it. :state(backward)Set on <neo-tabs> when the new tab sits before the previous one. :state(leaving)Set on the outgoing <neo-tabpanel> for the duration of its exit animation.
Slots # Name Description default <neo-tablist>, <neo-tab>, and <neo-tabpanel> children.
Events # Name Detail Bubbles Description neo-tabs-change{ value: string }yes Fires after the active tab changes.
CSS variables # Name Default Description --neo-tabs-list-bgcolor-mix(in srgb, var(--page-fg) 6%, transparent)Tablist pill background. --neo-tabs-list-padding0.25remPadding inside the tablist pill. --neo-tabs-list-border-width2pxTablist border width in forced-colors and high-contrast modes. --neo-tabs-radiusvar(--page-radius, 0.5rem)Tablist corner radius. --neo-tabs-focus-outline-width2pxFocus outline width. --neo-tabs-focus-outline-offset2pxFocus outline offset. --neo-tabs-tab-radiusmax(2px, calc(var(--neo-tabs-radius) - var(--neo-tabs-list-padding)))Tab corner radius. --neo-tabs-tab-padding-y0.4remTab vertical padding. --neo-tabs-tab-padding-x0.85remTab horizontal padding. --neo-tabs-tab-paddingvar(--neo-tabs-tab-padding-y) var(--neo-tabs-tab-padding-x)Tab padding shorthand. --neo-tabs-edge-tab-padding-xvar(--neo-tabs-tab-padding-x)Horizontal padding of the first and last tab in forced-colors and high-contrast modes. --neo-tabs-tab-colorvar(--muted, currentColor)Inactive tab text color. --neo-tabs-tab-hover-colorvar(--page-fg, currentColor)Tab text color on hover. --neo-tabs-tab-active-bgvar(--page-bg, #ffffff)Active tab background. --neo-tabs-tab-active-colorvar(--page-fg, currentColor)Active tab text color. --neo-tabs-tab-active-shadow0 1px 2px color-mix(in srgb, var(--page-fg) 16%, transparent)Active tab shadow. --neo-tabs-focus-ringvar(--accent, currentColor)Focus outline color. --neo-tabs-panel-padding0.85rem 0Panel padding.
Examples# Icons + labels# Each <neo-tab> accepts arbitrary children. Drop in a <neo-icon> next to the label and the tab's flex layout aligns them with the same gap as a <neo-button>.
Inbox
Messages
Notifications
Trash Inbox Your incoming mail, threaded by sender.
Messages Direct messages and chat threads.
Notifications Per-channel toggles for email, push, and digest.
Trash (unreachable in this demo)
No animation# Omit easing and the panel swap is instant. This is the default; the examples below opt into transitions and keyframe animations.
Overview Activity Reports Overview A snapshot of the project: open issues, recent commits, and the CI status.
Activity The chronological feed.
Reports Aggregated reports by week / month / quarter.
Custom animation# Point enter-animation and exit-animation at author-defined @keyframes. The tabs-tilt set here branches on the host's :state(forward) / :state(backward) custom state (set when the active tab changes), so the panel rotates and slides in from the side of travel.
General Appearance Advanced General Display name, timezone, language.
Appearance Theme, density, accent color.
Advanced Feature flags and developer options.
Custom styling# The --neo-tabs-* custom-property family swaps the default pill frame for any visual. Here a scoped <style> block sets those properties to turn the active pill into an accent-coloured underline, GitHub-style. Selection, keyboard navigation, and animation are unchanged.
Overview Issues Pull requests Actions README, recent commits, and the CI badge.
The open and closed issue tracker.
Pending and merged pull requests.
Workflow runs and scheduled jobs.
Auto-activate# Set auto-activate on the host so arrow keys commit the selection as focus moves, matching the classic WAI-ARIA radiogroup pattern.
Only observable with the keyboard: focus a tab, then press ← / → and the panel follows focus. A pointer behaves like a normal tab list.
Day Week Month Year Activity over the last 24 hours.
Activity over the last 7 days.
Activity over the last 30 days.
Activity over the last 365 days.
Vertical# Set orientation="vertical" on the host. The tablist stacks, arrow-key axes flip to ↑ /↓ , and the aria-orientation hint propagates to the tablist.
General Appearance Advanced General Display name, timezone, language.
Appearance Theme, density, accent color.
Advanced Feature flags and developer options.