Skip to content

Tabs

The CSS uses radio inputs + :has(input:checked) so vanilla HTML stays interactive without JavaScript. React wraps Base UI Tabs for ARIA semantics, arrow-key navigation, and controlled state.

Overview content.
Activity content.
Settings content.
<div class="tabs tabs-bordered">
<div class="tab-list" role="tablist">
<input
class="tab-input"
type="radio"
name="basic"
id="basic-1"
value="1"
checked
/>
<label class="tab" for="basic-1">Overview</label>
<input
class="tab-input"
type="radio"
name="basic"
id="basic-2"
value="2"
/>
<label class="tab" for="basic-2">Activity</label>
<input
class="tab-input"
type="radio"
name="basic"
id="basic-3"
value="3"
/>
<label class="tab" for="basic-3">Settings</label>
</div>
<div class="tab-panel" data-value="1">Overview content.</div>
<div class="tab-panel" data-value="2">Activity content.</div>
<div class="tab-panel" data-value="3">Settings content.</div>
</div>
Weekly breakdown.
<Tabs defaultValue="week" variant="boxed" size="sm">
<Tabs.List>
<Tabs.Tab value="day">Day</Tabs.Tab>
<Tabs.Tab value="week">Week</Tabs.Tab>
<Tabs.Tab value="month">Month</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="day">Daily breakdown.</Tabs.Panel>
<Tabs.Panel value="week">Weekly breakdown.</Tabs.Panel>
<Tabs.Panel value="month">Monthly breakdown.</Tabs.Panel>
</Tabs>

fullWidth stretches the list across the container and divides space evenly between tabs. Composes with both variants.

Inbox content.
Archive content.
Spam content.
<div class="tabs tabs-bordered tabs-full-width">
<div class="tab-list" role="tablist">
<input
class="tab-input"
type="radio"
name="full"
id="full-1"
value="1"
checked
/>
<label class="tab" for="full-1">Inbox</label>
<input class="tab-input" type="radio" name="full" id="full-2" value="2" />
<label class="tab" for="full-2">Archive</label>
<input class="tab-input" type="radio" name="full" id="full-3" value="3" />
<label class="tab" for="full-3">Spam</label>
</div>
<div class="tab-panel" data-value="1">Inbox content.</div>
<div class="tab-panel" data-value="2">Archive content.</div>
<div class="tab-panel" data-value="3">Spam content.</div>
</div>

Pair fullWidth with variant="boxed" for a segmented control that fills its row.

Weekly breakdown.
<Tabs defaultValue="week" variant="boxed" fullWidth>
<Tabs.List>
<Tabs.Tab value="day">Day</Tabs.Tab>
<Tabs.Tab value="week">Week</Tabs.Tab>
<Tabs.Tab value="month">Month</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="day">Daily breakdown.</Tabs.Panel>
<Tabs.Panel value="week">Weekly breakdown.</Tabs.Panel>
<Tabs.Panel value="month">Monthly breakdown.</Tabs.Panel>
</Tabs>

orientation="vertical" puts the tab strip on the left, panels on the right.

Profile settings.
<Tabs defaultValue="profile" orientation="vertical">
<Tabs.List>
<Tabs.Tab value="profile">Profile</Tabs.Tab>
<Tabs.Tab value="account">Account</Tabs.Tab>
<Tabs.Tab value="billing">Billing</Tabs.Tab>
<Tabs.Tab value="api">API keys</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="profile">Profile settings.</Tabs.Panel>
<Tabs.Panel value="account">Account settings.</Tabs.Panel>
<Tabs.Panel value="billing">Billing details.</Tabs.Panel>
<Tabs.Panel value="api">Personal access tokens.</Tabs.Panel>
</Tabs>