- Accordion
- Advanced Toast
- AlertMessage
- ArrowButton
- Arrows
- Avatar
- Backdrop
- Basic Toast
- Breadcrumb
- Button
- CardBackground
- Card
- Carousel
- Chapters
- ChatBody
- ChatButton
- ChatHeader
- ChatInput
- ChatMessageActions
- ChatMessageEditor
- ChatMessage
- ChatTypingIndicator
- ChatWindowCsatPrompt
- ChatWindowQuote
- ChatWindow
- CheckboxSelect
- Checkbox
- Checkboxes
- Chip
- ChoiceExpander
- Clickable
- ContentReview
- Countdown
- CriteriaDates
- CriteriaParticipants
- CriteriaTransports
- Date Field
- Datepicker
- Dropdown
- ElasticHeight
- ExpandableCard
- ExpandableText
- Filter
- FloatingLabelTextField
- Form Control
- Form Label
- Frame
- HamburgerIcon
- Heading
- Image
- JourneyCard
- LayerHeader
- Layer
- Link
- Loader
- Number Field
- PageNavigation
- Pagination
- Paragraph
- Password
- Phone Field
- Popin
- Portal
- ProductThumbnail
- Promises
- Prose
- Radio Group
- RadioSelect
- Radio
- Range
- Scrollbar
- Select
- SidebarLayout
- SliderFrame
- SparkleWrapper
- Spinner
- Switch
- Table
- Tabs
- Tag
- TextField
- Toggle
- Tooltip
- ValidationMessage
Tab - 1
Tab - 2
Tab - 3
Tab - 4
Tab - 5
Tab - 6
Tab - 7
Tab - 8
Tab - 9
Tab - 10
Tab - 11
Tab - 12
Tab - 13
Tab - 14
Tab - 15
Tab - 16
Tab - 17
Tab - 18
Tab - 19
Tab - 20
Tab - 21
Tab - 22
Tab - 23
Tab - 24
import { Tab, TabList, TabPanel, Tabs, TabsBody } from '../ui/tabs/Tabs';
export function TabsDemo() {
const tabs = new Array(24).fill(undefined).map((_, n) => ({ label: `${n + 1}`, value: n + 1 }));
const bgs = (count: number) => {
switch (count % 3) {
case 0:
return 'bg-lightSand';
case 1:
return 'bg-saffron';
case 2:
return 'bg-lavender';
default:
return 'bg-sienna';
}
};
return (
<Tabs selected={1} className="max-w-500">
<TabList>
{tabs.map((tab) => {
return <Tab key={tab.label} label={`Tab - ${tab.label}`} value={tab.value} />;
})}
</TabList>
<TabsBody>
{tabs.map((tab) => {
return (
<TabPanel key={tab.label} value={tab.value}>
<div className={`p-16 ${bgs(tab.value)}`}>Panel - {tab.label}</div>
</TabPanel>
);
})}
</TabsBody>
</Tabs>
);
}
Installation
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/arrows.json
Usage
import { Tab, TabList, TabPanel, Tabs, TabsBody } from '../ui/tabs/Tabs';
export default function TabsDemo() {
const tabs = new Array(3).fill(undefined).map((_, n) => ({ label: `${n + 1}`, value: n + 1 }));
const bgs = (count: number) => {
switch (count % 3) {
case 0:
return 'bg-lightSand';
case 1:
return 'bg-saffron';
case 2:
return 'bg-lavender';
default:
return 'bg-sienna';
}
};
return (
<Tabs selected={1}>
<TabList>
{tabs.map((tab) => {
return <Tab key={tab.label} label={`Tab - ${tab.label}`} value={tab.value} />;
})}
</TabList>
<TabsBody>
{tabs.map((tab) => {
return (
<TabPanel key={tab.label} value={tab.value}>
<div className={`p-16 ${bgs(tab.value)}`}>Panel - {tab.label}</div>
</TabPanel>
);
})}
</TabsBody>
</Tabs>
);
}API Reference
Main Tabs component
Main container of the component, orchestrates
| Prop | Type | Default | Description |
|---|---|---|---|
selected | number | undefined | Default selected tab |
children | children | undefined | |
compacted | boolean | false | Tightens the vertical spacing between the TabList and the TabsBody |
className | string | undefined | Additional className for the tabs container |
Tab List component
Displays the Tab components side by side. When the tab list overflows its container, left and right scroll buttons appear automatically. The buttons are keyboard-accessible (Space/Enter to scroll) and use aria-hidden / tabindex="-1" when scrolling in that direction is not possible.
| Prop | Type | Default | Description |
|---|---|---|---|
constrained | boolean | false | Whether or not to remove the spacers on the side of the tabs list |
className | string | undefined | Additional className for the scrollable element |
Tab component
The actual tab, clicking it will switch the current active tab and display its content in the TabPanel
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | undefined | Tab Heading text |
value | number | MANDATORY | Tab Heading index (can be 0 or 1 indexed) |
notification | ReactNode | undefined | Badge content rendered inside the tab label (e.g. a count or "!") |
onSelect | (context: {value:number, label:string}) => void | undefined | Callback on tab selection |
as | "div" | "h1" | "h2" | "h3" | "h4" | "h5"; | h2 | HTML tag to render the tab with |
className | string | undefined | Additional className for the root element in this component |
Tabs Body component
Container for the TabPanel components
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional className for the root element in this component |
Tab Panel component
Container for the content displayed when a tab is selected
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | MANDATORY | Index of the tab this panel is associated with |
className | string | undefined | Additional className for the root element in this component |
onSelect | (context: {value:number}) => void | undefined | Callback on tab panel selection |
Examples
Notification badge
Pass any ReactNode to the notification prop on a Tab to render a small badge next to the label. A number, a string like "!", or any inline element works. The badge colour adapts on hover and focus so it always stays legible against the active-pill background.
Overview
Messages3
Alerts!
Settings
import { Tab, TabList, TabPanel, Tabs, TabsBody } from '../ui/tabs/Tabs';
export function TabsNotificationDemo() {
return (
<Tabs selected={1}>
<TabList constrained>
<Tab label="Overview" value={1} />
<Tab label="Messages" value={2} notification={3} />
<Tab label="Alerts" value={3} notification="!" />
<Tab label="Settings" value={4} />
</TabList>
<TabsBody>
<TabPanel value={1}>
<div className="p-16 bg-lightSand">Overview panel</div>
</TabPanel>
<TabPanel value={2}>
<div className="p-16 bg-saffron">3 unread messages</div>
</TabPanel>
<TabPanel value={3}>
<div className="p-16 bg-lavender">Alerts panel</div>
</TabPanel>
<TabPanel value={4}>
<div className="p-16 bg-lightSand">Settings panel</div>
</TabPanel>
</TabsBody>
</Tabs>
);
}
Au ski
Au soleil
En croisière
Au ski
Sur les pistes
A la patinoire
Au soleil
A la plage
A la piscine
En croisière
Au Karting
Au minigolf
'use client';
import { Tab, TabList, TabPanel, Tabs, TabsBody } from '../ui/tabs/Tabs';
export function TabsWithinTabsDemo() {
const handleSelect = (context: { value: number }) => {
console.log('Selected tab:', context.value);
};
return (
<Tabs compacted selected={1}>
<TabList>
<Tab label="Au ski" value={1} onSelect={handleSelect} />
<Tab label="Au soleil" value={2} onSelect={handleSelect} />
<Tab label="En croisière" value={3} onSelect={handleSelect} />
</TabList>
<TabsBody>
<TabPanel value={1}>
<div className="bg-lightSand p-16">
<h4>Au ski</h4>
<Tabs selected={2} compacted>
<TabList constrained>
<Tab label="Sur les pistes" value={1} onSelect={handleSelect} />
<Tab label="A la patinoire" value={2} onSelect={handleSelect} />
</TabList>
<TabsBody>
<TabPanel value={1}>
<div>Sur les pistes</div>
</TabPanel>
<TabPanel value={2}>
<div>A la patinoire</div>
</TabPanel>
</TabsBody>
</Tabs>
</div>
</TabPanel>
<TabPanel value={2}>
<div className="bg-saffron p-16">
<h4>Au soleil</h4>
<Tabs selected={2} compacted>
<TabList constrained>
<Tab label="A la plage" value={1} onSelect={handleSelect} />
<Tab label="A la piscine" value={2} onSelect={handleSelect} />
</TabList>
<TabsBody>
<TabPanel value={1}>
<div>A la plage</div>
</TabPanel>
<TabPanel value={2}>
<div>A la piscine</div>
</TabPanel>
</TabsBody>
</Tabs>
</div>
</TabPanel>
<TabPanel value={3}>
<div className="bg-lavender p-16">
<h4>En croisière</h4>
<Tabs selected={2} compacted>
<TabList constrained>
<Tab label="Au Karting" value={1} onSelect={handleSelect} />
<Tab label="Au minigolf" value={2} onSelect={handleSelect} />
</TabList>
<TabsBody>
<TabPanel value={1}>
<div>Au Karting</div>
</TabPanel>
<TabPanel value={2}>
<div>Au minigolf</div>
</TabPanel>
</TabsBody>
</Tabs>
</div>
</TabPanel>
</TabsBody>
</Tabs>
);
}
Tab - 1
Tab - 2
Tab - 3
import { Tab, TabList, TabPanel, Tabs, TabsBody, TabSelect } from '../ui/tabs/Tabs';
export function TabsWithSelectDemo() {
const tabs = new Array(3).fill(undefined).map((_, n) => ({ label: `${n + 1}`, value: n + 1 }));
const bgs = (count: number) => {
switch (count % 3) {
case 0:
return 'bg-lightSand';
case 1:
return 'bg-saffron';
case 2:
return 'bg-lavender';
default:
return 'bg-sienna';
}
};
return (
<Tabs className="w-full" selected={1}>
<TabSelect aria-label="Choose a tab" className="md:hidden w-full" items={tabs} />
<TabList className="hidden md:flex">
{tabs.map((tab) => {
return <Tab key={tab.label} label={`Tab - ${tab.label}`} value={tab.value} />;
})}
</TabList>
<TabsBody>
{tabs.map((tab) => {
return (
<TabPanel key={tab.label} value={tab.value}>
<div className={`p-16 ${bgs(tab.value)}`}>Panel - {tab.label}</div>
</TabPanel>
);
})}
</TabsBody>
</Tabs>
);
}