Slots Configuration
Inject custom content at predefined positions through slots
Type Definition
interface SlotsConfig {
/**
* Title bar slots
*/
titleBar?: {
left?: ReactNode;
center?: ReactNode;
right?: ReactNode;
};
/**
* Sidebar slots
*/
sidebar?: {
header?: ReactNode;
footer?: ReactNode;
beforeNav?: ReactNode;
afterNav?: ReactNode;
};
/**
* Shell slots
*/
shell?: {
beforeContent?: ReactNode;
afterContent?: ReactNode;
};
}Title Bar Slots
Inject content at different positions in the title bar:
┌─────────────────────────────────────────────────┐
│ [left] [center] [right] [×] │
└─────────────────────────────────────────────────┘slots: {
titleBar: {
left: <SearchInput />,
center: <BreadcrumbNav />,
right: <UserMenu />,
},
},Example: Adding a Search Box
function SearchInput() {
return (
<input
type="search"
placeholder="Search..."
className="h-7 w-48 rounded border px-2 text-sm"
/>
);
}
slots: {
titleBar: {
left: <SearchInput />,
},
},Sidebar Slots
Inject content at different positions in the sidebar:
┌────────────┐
│ [header] │
├────────────┤
│[beforeNav] │
│ │
│ Nav Items │
│ │
│ [afterNav] │
├────────────┤
│ [footer] │
└────────────┘slots: {
sidebar: {
header: <WorkspaceSwitcher />,
beforeNav: <QuickActions />,
afterNav: <StorageIndicator />,
footer: <UserProfile />,
},
},Example: Adding User Info
function UserProfile() {
return (
<div className="flex items-center gap-2 p-3 border-t">
<img src="/avatar.png" className="w-8 h-8 rounded-full" />
<div>
<div className="text-sm font-medium">John Doe</div>
<div className="text-xs text-muted-foreground">john@example.com</div>
</div>
</div>
);
}
slots: {
sidebar: {
footer: <UserProfile />,
},
},Example: Adding Workspace Switcher
function WorkspaceSwitcher() {
return (
<select className="w-full p-2 border-b text-sm">
<option>Personal Workspace</option>
<option>Team Workspace</option>
</select>
);
}
slots: {
sidebar: {
header: <WorkspaceSwitcher />,
},
},Shell Slots
Inject content before and after the main content area:
┌────────────────────────────────────────┐
│ TitleBar │
├────────────┬───────────────────────────┤
│ │ [beforeContent] │
│ Sidebar ├───────────────────────────┤
│ │ Main Content │
│ ├───────────────────────────┤
│ │ [afterContent] │
└────────────┴───────────────────────────┘slots: {
shell: {
beforeContent: <AlertBanner />,
afterContent: <StatusBar />,
},
},Example: Adding Alert Banner
function AlertBanner() {
return (
<div className="bg-yellow-100 border-b border-yellow-200 px-4 py-2 text-sm text-yellow-800">
System maintenance scheduled for 10:00 PM tonight
</div>
);
}
slots: {
shell: {
beforeContent: <AlertBanner />,
},
},Example: Adding Status Bar
function StatusBar() {
return (
<div className="border-t px-4 py-1 text-xs text-muted-foreground flex justify-between">
<span>Connected</span>
<span>Last sync: 5 minutes ago</span>
</div>
);
}
slots: {
shell: {
afterContent: <StatusBar />,
},
},Complete Example
import { WorkspaceSwitcher } from './components/WorkspaceSwitcher';
import { UserProfile } from './components/UserProfile';
import { SearchInput } from './components/SearchInput';
import { StatusBar } from './components/StatusBar';
export const config = {
slots: {
titleBar: {
left: <SearchInput />,
},
sidebar: {
header: <WorkspaceSwitcher />,
footer: <UserProfile />,
},
shell: {
afterContent: <StatusBar />,
},
},
};Notes
Slot content is static and defined at configuration time. If you need dynamic content, manage state inside the slot component.
// Correct: manage state inside the component
function DynamicCounter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
slots: {
sidebar: {
footer: <DynamicCounter />,
},
},