Getting Started
Components
- Advanced Toast
- ArrowButton
- Arrows
- Avatar
- Backdrop
- Basic Toast
- Breadcrumb
- Button
- CardBackground
- Card
- ChatButton
- Checkbox
- Checkboxes
- Chip
- ChoiceExpander
- Clickable
- Date Field
- Dropdown
- ElasticHeight
- ExpandableCard
- Filter
- FormCheckbox
- Form Control
- Form Label
- HamburgerIcon
- Heading
- Image
- Link
- Loader
- Number Field
- Pagination
- Password
- Phone Field
- Popin
- Portal
- Prose
- Radio Group
- Radio
- Range
- Select
- SidebarLayout
- Spinner
- Switch
- Tabs
- Tag
- TextField
- ValidationMessage
CM
Project Dashboard
Welcome to your dashboard
This example shows SidebarLayout with composable header slots.
'use client';
import { Avatar } from '@/ui/Avatar';
import { Dropdown } from '@/ui/Dropdown';
import { SidebarLayout } from '@/ui/SidebarLayout';
import { Button } from '@/ui/buttons/Button';
const items = [
{ label: 'Home', icon: 'Home' as const, href: '#' },
{
label: 'Projects',
icon: 'HeartOutlined' as const,
items: [
{ label: 'Project A', href: '#' },
{ label: 'Project B', href: '#' },
{ label: 'Project C', href: '#' },
],
},
{ label: 'Team', icon: 'PeopleDouble' as const, href: '#' },
];
export function SidebarLayoutDemo() {
const user = { firstName: 'John', lastName: 'Doe' };
return (
<SidebarLayout items={items}>
<div data-slot="header-logo" className="text-white text-b3 font-semibold">
CM
</div>
<div data-slot="header" className="text-white text-h6">
Project Dashboard
</div>
<Dropdown data-slot="header-actions" aria-label="Open user actions">
<span data-slot="label" className="hidden md:inline text-body">
{user.firstName} {user.lastName}
</span>
<Avatar
data-slot="label"
alt={`${user.firstName} ${user.lastName}`}
className="w-40 h-40"
style={{ width: '40px', height: '40px' }}
/>
<Button size="small">Logout</Button>
</Dropdown>
<div>
<h1 className="text-h3 mb-16">Welcome to your dashboard</h1>
<p className="text-body">This example shows SidebarLayout with composable header slots.</p>
</div>
</SidebarLayout>
);
}
Installation
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/sidebar-layout.json
Usage
import { SidebarLayout } from '@/ui/SidebarLayout';
import { Dropdown } from '@/ui/Dropdown';
import { Avatar } from '@/ui/Avatar';
import { Button } from '@/ui/buttons/Button';
export function Component() {
const user = { firstName: 'John', lastName: 'Doe' };
return (
<SidebarLayout
items={[
{ label: 'Home', icon: 'Home', href: '#' },
{
label: 'Settings',
icon: 'Compare',
// Items with nested `items` render as buttons
items: [
{ label: 'Profile', href: '#profile' },
{ label: 'Account', href: '#account' },
],
},
{ label: 'Team', icon: 'PeopleDouble', href: '#team' },
]}
activeIndex={0}
>
<img data-slot="header-logo" alt="Brand" src="/brand.svg" />
<div data-slot="header">My Dashboard</div>
<Dropdown data-slot="header-actions">
<span data-slot="label" className="hidden md:inline text-body">
{user.firstName} {user.lastName}
</span>
<Avatar
data-slot="label"
alt={`${user.firstName} ${user.lastName}`}
className="w-40 h-40 cursor-pointer hover:opacity-80 transition-opacity"
style={{ width: '40px', height: '40px' }}
/>
<Button>Logout</Button>
</Dropdown>
<div>
<h1>Welcome to your Dashboard</h1>
<p>Your main content goes here.</p>
</div>
</SidebarLayout>
);
}API Reference
SidebarLayout Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | SidebarItem[] | - | Array of navigation items displayed in the sidebar (required) |
children | ReactNode | - | Main content and optional slotted header content (required) |
activeIndex | number | 0 | Index of the active sidebar item used by the indicator |
className | string | - | Additional CSS classes applied to the root container |
SidebarItem Structure
SidebarItem is a typed union:
- Link item: anchor props + required
href - Button item: button props (no
href)
| Property | Type | Required for | Description |
|---|---|---|---|
label | string | Both | Display text for the navigation item |
icon | IconicNames | Both | Icon name from the Trident Icons library |
href | string | Link items | Standard anchor URL for direct navigation |
items | SubItem[] | Optional | Nested links (when present, parent item renders as button) |
SubItem Structure
SubItem supports anchor attributes plus:
| Property | Type | Description |
|---|---|---|
label | string | Display text for the sub-item |
href | string | URL for the sub-item navigation |
Slots
Use data-slot on children passed to SidebarLayout:
| Slot | Description |
|---|---|
header-logo | Content rendered at the start of the header |
header | Main header content |
header-actions | Content rendered on the right side of the header |
Children without data-slot are rendered in the main content area.
Examples
With Custom Header
CM
Project Dashboard
Custom header example
This layout demonstrates custom `header-logo` and `header` slots.
'use client';
import { SidebarLayout } from '@/ui/SidebarLayout';
const items = [
{ label: 'Dashboard', icon: 'Home' as const, href: '#' },
{ label: 'Analytics', icon: 'CheckOutlined' as const, href: '#' },
];
export function SidebarLayoutWithHeaderDemo() {
return (
<SidebarLayout items={items}>
<div data-slot="header-logo" className="text-white text-b3 font-semibold">
CM
</div>
<div data-slot="header" className="text-white text-h6">
Project Dashboard
</div>
<div>
<h1 className="text-h3 mb-16">Custom header example</h1>
<p className="text-body">
This layout demonstrates custom `header-logo` and `header` slots.
</p>
</div>
</SidebarLayout>
);
}
Minimal Navigation
Minimal Layout
Minimal navigation
This layout demonstrates a compact SidebarLayout setup.
'use client';
import { SidebarLayout } from '@/ui/SidebarLayout';
const items = [
{ label: 'Home', icon: 'Home' as const, href: '#' },
{ label: 'Settings', icon: 'Compare' as const, href: '#' },
];
export function SidebarLayoutMinimalDemo() {
return (
<SidebarLayout items={items} activeIndex={1}>
<div data-slot="header" className="text-white text-h6">
Minimal Layout
</div>
<div>
<h1 className="text-h3 mb-16">Minimal navigation</h1>
<p className="text-body">This layout demonstrates a compact SidebarLayout setup.</p>
</div>
</SidebarLayout>
);
}
Notes
Responsive Behavior
- Desktop: Features a collapse button with animated indicator that follows the active navigation item using CSS anchor positioning
- Mobile: Replaces collapse button with a hamburger menu that slides the sidebar in from the left
- The sidebar automatically collapses on mobile and can be toggled open with the hamburger icon
- Animations use CSS transitions for smooth state changes
Navigation Patterns
- Navigation items with a
hrefproperty render as anchor links for direct navigation - Items with nested
itemsrender as buttons and display a collapsible list of sub-navigation links - The active navigation indicator uses CSS anchor positioning to smoothly track the currently active item
- Sub-items are automatically hidden when the sidebar is collapsed and marked as
inertfor accessibility
Header Composition
- Header content is fully composable through slots (
header-logo,header,header-actions) - A common pattern is to render
Dropdownwith slotted labels and action buttons insideheader-actions - This keeps identity/logout logic outside
SidebarLayoutand makes the layout reusable
Accessibility
- Full keyboard navigation support with visible focus indicators
- ARIA labels for all interactive elements (expand/collapse, open/close menu)
- Uses
inertattribute to prevent interaction with collapsed sub-items - Semantic HTML with proper landmark regions (navigation, complementary, main)
- Screen reader friendly with descriptive labels that update based on state
Styling Customization
- Use the
classNameprop to add custom Tailwind classes to the root container - The component uses Tailwind utility classes extensively for responsive design
- For deeper customization, copy the component source and modify the internal classes
Performance
- Uses
useStatefor local state management (collapse state) - Callbacks are memoized with
useCallbackto prevent unnecessary re-renders - CSS transitions handle all animations without JavaScript animation frames