Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

    Components

    Tabs

    The Tabs are radio inputs and the Panels are just divs that show and hide based on the radio inputs' :checked state.

    Full supportSupported since v123.Full supportSupported since v120.Full supportSupported since v17.5.

    Anatomy

    Profile settings and information.
    General account settings.
    • <Tabs>

      Container element.

    • <Tabs.Item>

      A visually hidden radio input that holds a tab's state.

    • <Tabs.Tab>

      A tab.

    • <Tabs.Panel>

      The panel of the selected tab.

    Basics

    Profile settings and information.
    General account settings.
    Manage your notifications.
    ---
    import { Tabs } from "@opui/astro"
    ---
    <Tabs name="basic-tabs">
    <Tabs.Item open>
    <Tabs.Tab>Profile</Tabs.Tab>
    <Tabs.Panel>Profile settings and information.</Tabs.Panel>
    </Tabs.Item>
    <Tabs.Item>
    <Tabs.Tab>Settings</Tabs.Tab>
    <Tabs.Panel>General account settings.</Tabs.Panel>
    </Tabs.Item>
    <Tabs.Item>
    <Tabs.Tab>Notifications</Tabs.Tab>
    <Tabs.Panel>Manage your notifications.</Tabs.Panel>
    </Tabs.Item>
    </Tabs>
    <div class="ui-tabs" role="tablist">
    <input
    name="basic-tabs"
    aria-controls="panel-3"
    checked
    class="ui-tab-input"
    id="tab-3"
    type="radio"
    /><label for="tab-3" class="ui-tab-label" role="tab">Profile</label>
    <div
    aria-labelledby="tab-3"
    id="panel-3"
    class="ui-tab-panel"
    role="tabpanel"
    >
    Profile settings and information.
    </div>
    <input
    name="basic-tabs"
    aria-controls="panel-4"
    class="ui-tab-input"
    id="tab-4"
    type="radio"
    /><label for="tab-4" class="ui-tab-label" role="tab">Settings</label>
    <div
    aria-labelledby="tab-4"
    id="panel-4"
    class="ui-tab-panel"
    role="tabpanel"
    >
    General account settings.
    </div>
    <input
    name="basic-tabs"
    aria-controls="panel-5"
    class="ui-tab-input"
    id="tab-5"
    type="radio"
    /><label for="tab-5" class="ui-tab-label" role="tab">Notifications</label>
    <div
    aria-labelledby="tab-5"
    id="panel-5"
    class="ui-tab-panel"
    role="tabpanel"
    >
    Manage your notifications.
    </div>
    </div>

    Accessibility

    The tab system uses standard radio inputs and labels, so we get group management and keyboard support for free!

    Tab List

    ElementAttributeDescription
    .ui-tabsrole="tablist"Identifies the element as a container for a set of tabs.
    inputnameGroups the radio buttons together for exclusive selection.
    labelrole="tab"Identifies the element as a tab to assistive technology.

    Tab Panel

    The content area associated with a tab:

    AttributeValueDescription
    role"tabpanel"Identifies the element as a tab panel.
    aria-labelledbystringLinks the panel to its trigger ID.

    Keyboard Interaction

    • Tab: Moves focus to the active tab trigger (the radio button). Pressing Tab again moves focus out of the tab list to the next focusable element.
    • Right Arrow / Down Arrow: Moves focus to the next tab and activates it.
    • Left Arrow / Up Arrow: Moves focus to the previous tab and activates it.

    API

    Tabs API

    PropTypeDefaultDescription
    namestring-The name shared by the tab inputs. Generated when omitted.

    Slots

    SlotDescription
    defaultThe tab items.

    Tabs item API

    PropTypeDefaultDescription
    namestring-Overrides the name shared by the tab inputs.
    openbooleanfalseSelects the tab initially.
    panelIdstring-The id of the panel. Generated when omitted.
    tabIdstring-The id of the input. Generated when omitted.

    Slots

    SlotDescription
    defaultThe tab and the panel.

    Tabs tab API

    PropTypeDefaultDescription
    tabIdstring-The id of the input it labels. Set by the item.

    Slots

    SlotDescription
    defaultThe tab label.

    Tabs panel API

    PropTypeDefaultDescription
    panelIdstring-The id of the panel. Set by the item.
    tabIdstring-The id of the tab input that labels it. Set by the item.

    Slots

    SlotDescription
    defaultThe panel content.

    Browser support

    Full supportSupported since v123.Full supportSupported since v120.Full supportSupported since v17.5.

    See also the full browser support guide.

    Installation

    @layer components.root {
    :where(.ui-tabs) {
    --_accent-color: var(--primary);
    --_bg-color: transparent;
    align-items: flex-start;
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--size-1);
    position: relative;
    & > .ui-tab-input[type="radio"] {
    /* utils > .ui-sr-only */
    /* TODO: use mixin for this when available */
    block-size: 1px;
    clip-path: inset(50%);
    inline-size: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    &:checked {
    /* Checked Tab */
    & + [role="tab"],
    & + .ui-tab-label {
    border-block-end-color: var(--_accent-color);
    color: var(--_accent-color);
    /* Checked Panel */
    & + [role="tabpanel"],
    & + .ui-tab-panel {
    display: block;
    }
    }
    }
    &:focus-visible {
    & + [role="tab"],
    & + .ui-tab-label {
    --focus-ring-color: var(--text-muted);
    --focus-ring-offset: calc(-1 * var(--size-2));
    outline: var(--focus-ring-width) var(--focus-ring-style)
    var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
    }
    }
    }
    /* Tab */
    & > [role="tab"],
    & > .ui-tab-label {
    align-items: center;
    background-color: transparent;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    color: var(--text-muted);
    cursor: pointer;
    display: inline-flex;
    font-weight: 600;
    justify-content: center;
    line-height: var(--font-lineheight-4);
    order: 1;
    padding: var(--size-2) var(--size-3);
    position: relative;
    transition: color 0.1s;
    user-select: none;
    &:hover {
    background-color: light-dark(
    oklch(from var(--_accent-color) calc(l * 0.75) none h / 5%),
    oklch(from var(--_accent-color) calc(l * 1.25) none h / 5%)
    );
    }
    }
    /* Tab Panel */
    & > [role="tabpanel"],
    & > .ui-tab-panel {
    display: none;
    inline-size: 100%;
    order: 2;
    }
    }
    }