Tabs
A component for creating tab elements. Only interaction behavior is provided — visual styling is intentionally left for you to customize.
Usage
Provided as Tabs from the @lism-css/ui package.
Import
import { Tabs } from '@lism-css/ui/react'; Props
| Property | Description |
|---|---|
<Tabs.Root> variant | Outputs the c--tabs--{variant} class. |
<Tabs.Root> tabId | A string ID used as the value for aria-controls to identify each tab. |
<Tabs.Root> defaultIndex | Specifies which tab to open initially. |
<Tabs.Root> listProps | Props passed to the list element (c--tabs_list) wrapping the tab buttons. |
Structure
<Tabs.Root> <Tabs.Item> <Tabs.Tab>Tab label</Tabs.Tab> <Tabs.Panel>...Contents...</Tabs.Panel> </Tabs.Item></Tabs.Root>Only <Tabs.Tab> and <Tabs.Panel> are recognized as children of <Tabs.Item>. Both must always be used together.
Source Code
The source code is available on GitHub.
Examples
Basic example
Tab 01: Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
<Tabs.Root> <Tabs.Item> <Tabs.Tab>Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab>Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="l" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>Specifying the initially open tab
Use defaultIndex on <Tabs.Root> to specify which tab is open by default.
(Index numbers start from 1.)
Tab 02: Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut. Aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint.
<Tabs.Root defaultIndex={2}> <Tabs.Item> <Tabs.Tab>Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab>Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="l" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>Side-by-side tab layout
Setting grid-template: 'list panel' auto / auto 1fr; on <Tabs.Root> (c--tabs) places the tab list and content side by side.
At the same time, changing the tab list (c--tabs_list) buttons to stack vertically (flex-direction: column;) achieves the following layout.
@sm and aboveTab 01: Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
<Tabs.Root gt={[null, '"list panel" auto / auto 1fr']} listProps={{ fxd: [null, 'column'] }}> <Tabs.Item> <Tabs.Tab>Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab>Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="l" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>Opt-in
Style variation examples
c--tabs_tab exposes --_isSelected and --_notSelected variables, which are handy for styling.
(They can be used in the same way as --_isHov and --_notHov from set--var:hov.)
Here are a few styling examples.
c--tabs--line
@layer lism-component {
.c--tabs--line > .c--tabs_list {
/* Memo: ov-x='auto' の時に margin がネガティブだと崩れるので、box-shadowで表現する。 */
box-shadow: inset 0 -2px 0 var(--divider);
}
.c--tabs--line .c--tabs_tab {
font-size: var(--fz--s);
background-color: transparent;
box-shadow: var(--_isSelected, inset 0 -2px 0 0 currentColor);
}
} variant='line'Tab 01: Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
<Tabs.Root variant="line"> <Tabs.Item> <Tabs.Tab>Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab>Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="l" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>c--tabs--emboss
@layer lism-component {
.c--tabs--emboss > .c--tabs_list {
justify-self: center;
padding: 4px;
font-size: var(--fz--s);
background-color: var(--base-2);
border-radius: var(--bdrs--20);
}
.c--tabs--emboss .c--tabs_tab {
padding: 0.25em 0.75em;
border-radius: calc(var(--bdrs--20) - 2px); /* 親の bdrs - (親のpadding / 2) */
background-color: var(--_isSelected, var(--base));
box-shadow: var(--_isSelected, var(--bxsh--10));
}
} variant='emboss'Tab 01: Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
<Tabs.Root variant="emboss"> <Tabs.Item> <Tabs.Tab>Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab>Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="l" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>Fixed height
An example of how to fix the overall tabs height to match the tallest content panel.
@layer lism-component {
[data-tabs-keep-height] > [aria-hidden='true'] {
display: block;
visibility: hidden;
opacity: 0;
}
} Tab 01: Lorem ipsum dolor sit amet. Consectetur adipiscing elit, sed do eiusmod tempor Incididunt ut. Labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
<Tabs.Root data-tabs-keep-height g="15"> <Tabs.Item> <Tabs.Tab px="10">Tab 1</Tabs.Tab> <Tabs.Panel> <DummyText pre="Tab 01: " /> </Tabs.Panel> </Tabs.Item> <Tabs.Item> <Tabs.Tab px="10">Tab 2</Tabs.Tab> <Tabs.Panel> <DummyText length="xl" offset={1} pre="Tab 02: " /> </Tabs.Panel> </Tabs.Item></Tabs.Root>