A floating sidebar with submenus. Adapt the Sidebar components from @kamod-ch/ui to your navigation, branding and page content. Replace sample destinations with your own routes, then check the mobile layout and keyboard navigation in the live demo. The source and setup steps show which files belong to this variant.
Getting started
Add this block
Download this variant into your Preact project, install the dependencies you are missing and connect your own navigation and page content. The source stays local, so you can change its layout without introducing another application framework.
1. Copy the block
Download this variant and extract its
sidebar-04folder intosrc/components/blocks. Install the dependencies below, then import the component. The folder includes its own helpers and demo data; no other sidebar variants are needed. Relative imports are already set up inside the folder, so you can move it as a unit and replace the sample navigation and content with your own. The archive already contains the outersidebar-04/folder: extract it once, rather than creating a second nested folder with the same name. The import examples assumesrc/App.tsx.Download blockInstall dependencies14 files · source ZIP·Prefer manual copying? Open the Showcase’s Code tab and copy each listed file into the same folder structure above. Its labels are the destination paths inside
sidebar-04/, and its imports already match the download. Keep the included license with your copy.2. Install missing dependencies
Install only what your app does not already have. Preact renders the block, Kamod UI provides its interactive components, and Icons supplies its icons. Themes and Signals support the shared Kamod setup.
pnpm add @kamod-ch/ui @kamod-ch/icons preact @kamod-ch/themes @preact/signals3. Set up styles and import
Follow the theme and Tailwind setup. Import your global stylesheet and make sure Tailwind scans the copied source and Kamod components. Keep your existing setup if the app already uses Kamod.
import { Sidebar04 } from "./components/blocks/sidebar-04";The
@kamod-ch/blocks/sidebar/sidebar-04path identifies source in this repository; the blocks package is private. Use the local import above rather than trying to install that path as a published package.Check the first render: the sidebar, borders and page background should follow your app’s theme. If the layout appears unstyled, check the global CSS import and Tailwind source detection before changing the block’s classes. If an import fails, first compare your folder paths with the copy list; renaming only one file can break its relative imports.
Integration
Usage
Start with the complete preview composition, then adapt its local source to your app. The exported Sidebar04 takes no props; navigation, content and behavior are configured inside your copied files.
How this composition works
Think of this block as an editable starting layout. Rendering <Sidebar04 /> runs the JSX already written in your copied file: its sidebar, header, sample data and placeholder content. The supplied wrapper does not read navigation props or children, so your own content needs to be connected inside that composition first.
A block such as Application Shell 1 exposes a defined API for navigationGroups, breadcrumbs and children. These sidebar variants instead expose their arrangement as source you can edit. That lets a documentation sidebar, a two-pane layout and a settings dialog each keep their own structure without fitting every difference into one configuration object. You get direct control over the layout, with the responsibility of wiring it to your app.
- The file you render owns the composition
- Open
sidebar-04.tsxto see how the pieces fit together. Keep its provider and layout structure while replacing the parts you need. TheSidebar04wrapper is your local page; the coreSidebarinside it is a configurable UI component. - Data and helper props still do the work
- The no-props entrypoint does not remove the inner components’ APIs. Your copied file passes data and options to the helpers it uses. Update the sample values in
data/or pass application values at those call sites. Follow Adapt the local composition for this variant’s example and Local props and data for the supported inputs. - Your content goes into the existing page area
- This variant uses
DashboardShell. Itschildrenreplace the placeholder panels while retaining the surrounding shell. Your router decides which page to show; the block does not choose routes or fetch your application data. See Connect your application.
A small content change looks like this. This is an excerpt to edit inside your copied file, keeping the rest of its JSX in place. It is not a replacement for the whole block or a new prop on Sidebar04.
// Inside sidebar-04.tsx; keep existing shell props.
<DashboardShell>
<div class="p-4">Your page content</div>
</DashboardShell>You can introduce your own props later. If multiple routes need the same layout, add a typed children prop or navigation inputs to your local Sidebar04, then explicitly forward them to the relevant helpers. The downloaded wrapper does not do that automatically. Start by rendering the original below, then make the local edits one step at a time.
Render the block
Render the block once in your page or route layout. It already includes its own SidebarProvider, so you do not need another provider around this example.
import { Sidebar04 } from "./components/blocks/sidebar-04";
export const App = () => <Sidebar04 />;Adapt the local composition
Your copied sidebar-04.tsx contains the complete composition. Start with its imports from data/ to replace sample labels and destinations, then update the local components that consume them. The snippet below replaces one part of that file; keep the surrounding provider and layout in place.
// In sidebar-04.tsx; keep the surrounding layout.
<NavMain collapsible={false} items={[{
title: "Projects", url: "/projects", icon: "frame", isActive: true,
items: [{ title: "Overview", url: "/projects/overview" }],
}]} />These are local edits, not props to pass to <Sidebar04 />. See Local props and data for the helpers this variant actually includes and their supported inputs.
Connect your application
Pass your page content as children to the existing DashboardShell to replace its placeholder content. Supply breadcrumbs from the current route, with the current page last. Custom children replace the demo’s padded content wrapper too, so add your own spacing.
// In sidebar-04.tsx; keep existing layout props.
<DashboardShell
breadcrumbs={[
{ label: "Workspace", href: "/" },
{ label: "Projects" },
]}
>
<div class="flex flex-1 flex-col gap-4 p-4">
<h1 class="text-2xl font-semibold">Projects</h1>
<p>Your routed content goes here.</p>
</div>
</DashboardShell>- Routing and actions. Real URLs navigate normally;
#links are placeholders. For client-side routing, adapt the local links to your router and derive active styling from its current route. Expanding a navigation group does not select a destination. Connect any search, account or form controls you keep to real application handlers. - Close mobile navigation deliberately. The demo link helper only prevents
#navigation. It does not close the mobile sheet after a client-side route change. In a helper rendered inside the existing provider, useuseSidebar()and callsetOpenMobile(false)after handling an ordinary destination click. Preserve modified clicks and avoid closing the sheet when a user only expands a branch. - Preserve the layout. Keep the existing main landmark and keep sidebar controls inside their existing provider. Keep the composition mounted across page changes to retain its local UI state. Review this variant’s responsive behavior before moving controls; desktop and mobile navigation can differ. Follow the production checklist before shipping.
API reference
Props and data
Sidebar04 is a ready-made demonstration page with no public props. The reference below describes the local helpers and data you can configure after copying the source. Definitions come directly from the implementation; descriptions explain where your application takes over. Start with the component or data shape you want to change, then follow its type link to the complete definition. Keep sample values in data/ separate from the behavior in your copied components. This lets you replace labels and destinations without rewriting the surrounding layout in sidebar-04.tsx.
import type from the corresponding copied file when typing your own data or component inputs. This reference describes the shipped source; changes in your local files will not update this page.TypeScriptLocal props and data
? means the field may be omitted, not that every optional field has a fallback value. When a field accepts an array, its required marker means you must supply the array; check the helper’s behavior before using an empty [].| Prop / type | Description |
|---|---|
label | Text for one breadcrumb in the header’s ordered trail. Place the current page last: that final item is always rendered as page text, even if it has an href. Earlier items become links only when they supply href. Keep labels concise and distinct within the trail because they also serve as rendering keys. |
href | Optional URL for an intermediate breadcrumb. When present on a non-final item it renders a BreadcrumbLink; when omitted, the item renders as page text instead. The last breadcrumb never becomes a link, even if a URL is supplied. Set real parent destinations here rather than relying on the fallback trail’s # placeholder. |
hiddenOnMobile | Hides this breadcrumb and its preceding separator below 768px; omitted or false keeps them visible. Use it for intermediate hierarchy levels when space is limited. The helper does not protect the final item from this flag, so leave it unset on the current page. Review the whole trail on mobile after hiding items so the remaining context is still understandable. |
children | Your page content rendered directly beneath DashboardShell’s optional breadcrumb header inside SidebarInset. Supplying content replaces the placeholder panels completely; add your own padding, layout and loading states around it. Null or undefined falls back to the selected placeholder arrangement. Use this on the local DashboardShell in your copied composition, not as a prop on the exported SidebarXX wrapper. |
breadcrumbParent | Parent label in the fallback two-level breadcrumb trail, used when breadcrumbs is omitted or empty. Defaults to Build Your Application and is hidden below 768px; an empty string removes it. Its fallback link points to #. Use the breadcrumbs array instead when the parent needs a real destination or the hierarchy contains more levels. |
breadcrumbPage | Current-page label in the fallback breadcrumb trail; defaults to Data Fetching. It stays visible on mobile and is rendered as page text rather than a link. This value is ignored when a non-empty breadcrumbs array is supplied. Update it from your page context, or switch to that array for a fully specified hierarchy. |
breadcrumbs | Ordered trail of labels and optional destinations; place the current page last. A non-empty array replaces breadcrumbParent and breadcrumbPage, while an empty array still uses their fallback values rather than hiding the trail. Use hiddenOnMobile selectively on intermediate items. To remove the whole header and its toggle, use showHeader instead. |
headerClass | Class string replacing the header’s default flex layout, height, border and horizontal padding. Include any structural classes you still need when overriding it; this is not merely appended to the defaults. stickyHeader independently adds sticky positioning, top offset, stacking and background classes. The value has no visible effect when showHeader is false. |
contentClass | Extra classes merged into the grid, list and squares placeholder wrappers, alongside their flex layout and padding classes. This does not style custom children or the outer SidebarInset. The centered placeholder uses its own fixed wrapper and ignores this value. Once you supply real content, put its classes on your own elements instead. |
triggerClass | Class string passed to the breadcrumb header’s SidebarTrigger, replacing the default -ml-1 margin. Use it to adjust the toggle’s position within your chosen header layout while retaining the core trigger behavior. An empty string removes that default margin. It has no visible effect when showHeader is false and does not control whether the sidebar is open. |
headerInner | Wraps the sidebar toggle, separator and breadcrumbs in a shared inner row; defaults to false. Enable it when the header needs an outer surface and a separately padded group of controls. The row receives flex alignment plus headerInnerClass, whose default is px-3. This changes markup and spacing only, not navigation or sidebar state. |
headerInnerClass | Classes merged with the inner header row’s fixed flex alignment and gap when headerInner is true. Defaults to px-3; supplying a value replaces that default padding rather than appending to it. Use this for the row around the toggle, separator and breadcrumbs, while headerClass styles the outer header. It is ignored when the inner row is disabled. |
stickyHeader | Adds sticky top positioning, z-index and the theme background to the breadcrumb header; defaults to false. It keeps that header visible within the applicable scroll container rather than making the entire page fixed. Review ancestor overflow when integrating the copied layout because it affects sticky behavior. No sticky header is rendered when showHeader is false. |
showHeader | Controls whether DashboardShell renders its breadcrumb header, separator and sidebar toggle; defaults to true. Setting it to false leaves the content area intact but also removes that built-in toggle. If your composition supplies its own header, place a SidebarTrigger there when users still need to open or collapse navigation. This flag does not hide the sidebar itself. |
placeholder | Selects the demonstration content shown when children is null or undefined; defaults to grid. Choose grid for three summary panels and a larger area, list for repeated rows, squares for a tile grid or centered for a narrower centered composition. These are static visual placeholders, not loading or data-fetching components. The option is ignored as soon as you supply your own content. |
contentPaddingTop | Controls top padding on the grid, list and squares placeholder wrappers; defaults to true. Setting it to false retains their side and bottom padding but removes the top gap, useful when matching a particular header composition. It does not affect custom children. The centered placeholder has its own fixed padding and also ignores this option. |
items | Primary navigation rows, in display order, with icon-map keys and optional child links. Each row without children navigates directly; rows with children follow the collapsible setting. Supply your own data and derive active markers from your router because NavMain does not discover the current route. An empty array leaves the Platform label with no destination rows. |
collapsible | Controls how NavMain presents items that have children; defaults to true. With true, clicking the parent toggles its submenu and an active parent starts open. With false, the parent becomes a normal link and its child links remain visible. Items without children stay links in either mode. This option controls navigation submenus, not the sidebar’s desktop or mobile open state. |
icon | Key selecting a component from the copied navigation-icons.ts map. Use one of that map’s supported keys; an arbitrary icon name or SVG string will not resolve to a component. To introduce a new symbol, import a Kamod icon and add it to the map before using its key in your data. The adjacent text remains the destination’s visible label. |
items | Optional nested destinations for this primary navigation item. Omit it or supply an empty array to keep the parent as a direct link. NavMain renders children inline, optionally behind a disclosure, while NavMainDropdowns places them in a dropdown. These children are NavigationLink entries, so this shape supports one child level rather than an arbitrary recursive tree. Child active markers are not rendered by these submenu helpers. |
title | Visible destination label used in navigation rows and, where supported, collapsed-sidebar tooltips. Choose short, distinguishable names and keep titles unique within each list because the helpers also use them as rendering keys. Changing a title does not change its URL or select the current route. |
url | Destination used when the item renders as a link. Replace the demo’s # with an application route or a real URL; the shared click handler prevents navigation only for that exact placeholder. A parent with children may instead act as a disclosure or dropdown trigger, so its URL is not necessarily followed. Router-specific link components must be wired into the copied helper. |
isActive | Optional current-destination marker; omitting it leaves the item unmarked. Documentation links and direct primary links use it for their active styling and aria-current. Collapsible groups use active data for their initial open state, not as controlled disclosure state. Nested primary links, dropdown entries and Favorites do not currently read this marker; adapt those renderers if you need route highlighting there. |
name | Workspace name displayed in the selected-team trigger and dropdown choices. TeamSwitcher also uses this value as its selection identity and rendering key, so names must be unique and stable while the list is mounted. Renaming or removing the selected name makes the display fall back to the first available team. If names are editable in your product, consider adapting the helper to use a separate stable ID. |
logo | Workspace mark shown both in the selected-team trigger and in the dropdown list. The exact string kamod renders the included Kamod brand icon; any other string is displayed as text, such as initials or an emoji. This is not an image URL prop. Adapt the logo renderer if you need uploaded logos or another image component. |
plan | Secondary text displayed beneath the selected workspace’s name, such as Enterprise or Personal workspace. The switcher treats it as a display label only; it does not enforce subscription permissions or determine available features. Keep it short enough for the compact trigger, where longer text is truncated. |
teams | Workspaces available in the switcher, in display order. The first entry is selected initially, and an empty array hides the switcher entirely. Selection is stored locally by team name; if that name disappears from the array, the display falls back to the first entry. Choosing a team does not change routes, fetch workspace data or persist an account preference—connect those actions in your copied switcher. |
Configure the core Sidebar directly in your copied page: side chooses left or right, variant controls the surface, and collapsible chooses offcanvas, icon or none. The references here list only types included in this variant’s download. Inherited types are shown separately: NavigationItem adds an icon and optional children to NavigationLink, which owns the required title and URL. Read both definitions when building a navigation item.
Data type reference
Expand a definition to copy its exact TypeScript shape. Required fields are listed below each summary for fields declared in that definition. The code header shows the file's installation path; copy the definition with the button beside it. For intersections, also inspect the referenced base type’s required fields. Local types can be imported from the same files as your copied components; they are not added to the zero-prop page wrapper.
BreadcrumbConfiglabelDashboardShellPropsNavMainPropsitemsNavigationItemiconNavigationLinktitle, urlTeamname, logo, planTeamSwitcherPropsteamsVariant details
Floating navigation surface
A floating, wider sidebar separates navigation from the surrounding page with an inset edge. Its submenus are expanded. The composition still uses off-canvas collapse; floating changes the visual treatment, not the navigation model.
Edit sidebar-04.tsx for layout and data/ for example content. Reusable interactions live in components/. Each variant is an explicit composition; there is no configuration switch or dependency on another variant.
A closer look
About this block
A floating application sidebar that gives navigation its own visual surface beside the workspace. It retains the visible submenu structure of Sidebar 3 but uses a wider desktop navigation area and a lighter separation from the main header. Its value is the spatial distinction between navigation and content, rather than a new navigation mechanism.
When to choose this variant
- Where this layout adds value
- Useful when the page background should remain visible around navigation, or when workspace labels and child destinations benefit from more horizontal room. The floating treatment can help a dashboard's navigation feel separate from dense tables, editors or report content without adding another application-level toolbar.
- The tradeoff to consider
- The wider rail leaves less room for the workspace on intermediate desktop widths. Visible child links still consume vertical space. Floating is a visual variant, not a guarantee that the sidebar can be freely positioned inside any container; preserve the core layout relationship and test the actual host page.
Compare nearby variants
Choose by the way people move through your app, not only by the preview’s appearance. These nearby variants change a specific part of that experience; they are alternatives, not files you need to install alongside this block.
- Sidebar 3 →
- Provides the same visible parent/child structure with a conventional sidebar edge and bordered header, leaving more room for content.
- Sidebar 8 →
- Emphasizes an inset main workspace rather than a floating navigation surface, and includes project, utility and account sections.
Composition and customization
SidebarProvider sets the desktop sidebar width to 19rem and Sidebar uses variant="floating". TeamSwitcher and NavMain provide workspace and route navigation, with collapsible=false on the navigation helper. DashboardShell removes its placeholder's top padding and uses a header without the standard bottom border.
In the downloaded folder, index.ts exports Sidebar04. Its sidebar-04.tsx owns the arrangement. Any included helpers live in components/, fixtures in data/, and any included brand artwork in branding/. These paths describe your installation folder, which is generated from the actual implementation with its relative imports rewritten together.
Edit the composition where it is assembled. The exported wrapper does not accept a navigation configuration or forward children. Its inner components still have their own inputs. Replace data at their call sites and insert your content in the existing page area; the Usage guide shows the appropriate insertion point for this variant. You can introduce a typed wrapper API later if multiple routes need to reuse your adapted layout.
How interaction and state work
The sidebar uses the default off-canvas collapse mode on desktop, rather than the icon rail used by Sidebar 7. NavMain's child links remain expanded when the sidebar is visible. Team selection is local presentation state, and the sample destinations do not yet navigate through an application router.
- Presentation state belongs to the layout
- An open menu, expanded branch or selected demo value describes the interface at that moment. It does not automatically load data, authorize access or change the URL. Preserve useful local UI state while letting your application own the current page and real records.
- Route state belongs to your application
- Derive active destinations, page content and breadcrumbs from one route or selection model. An
isActiveflag supplies styling; it is not a router. Where a helper initializes a disclosure withdefaultOpen, decide whether later route changes should also update that disclosure.
Inspect Local props and data before wiring a callback. Only the inputs documented for the copied helper are available; introducing another callback also requires updating its implementation.
Responsive behavior
The floating desktop treatment gives way to the core mobile sheet below 768px. Check long submenu labels in both presentations.
Below 768px, collapsible core sidebars use the mobile sheet. Desktop open and mobile openMobile are separate states in SidebarProvider; restoring a desktop preference does not open the sheet. Static regions using collapsible="none" follow their own layout and visibility classes instead.
Test the space left for your actual content, not just the empty panels. Long navigation labels, a wide data table and a short viewport can expose different constraints. Let text wrap where it carries meaning, keep any necessary scrolling local to its content, and offer another way to reach essential controls when a secondary pane is hidden.
Accessibility
Verify text contrast on both the floating surface and the surrounding page. The visual gap should not obscure which control opens the navigation after collapse; retain the labeled header toggle and a visible keyboard focus outline.
- Current location and meaningful names
- Use real links for destinations and buttons for actions. Set
aria-current="page"on the current destination; visible selection alone is insufficient. Give icon-only controls meaningful names, and make breadcrumbs agree with the page being shown rather than leaving their sample labels unchanged. - Keyboard, focus and content landmarks
- Retain core disclosure, menu and overlay behavior. Check Tab, Shift+Tab, Enter, Space and Escape where applicable, including focus return after dismissal. The existing page area already provides a main landmark; insert content within it rather than adding nested
mainelements. Give distinct navigation regions meaningful labels when your adaptation contains more than one. The core provider also registersCtrl/Cmd+Bto toggle navigation; check this shortcut against your application’s editor or other global shortcuts, and avoid mounting duplicate providers for the same layout.
Validate your finished integration at 320px, 768px, 1024px and 1440px, with keyboard-only input, 200% zoom, both color modes and long real content. Check short screens and the on-screen keyboard as well. Reusing the primitives helps preserve behavior, but cannot guarantee accessibility after your content or structure changes.
Replace the demo behavior
Choose the sidebar width alongside your real page's minimum useful width. Keep the floating frame and workspace spacing coordinated, then replace demo teams and routes. When inserting content through DashboardShell children, add your own content padding; the placeholder's padding choices do not wrap custom children automatically.
- Replace demo navigation. Supply real URLs: the shared
stopNavigationhelper only cancels links whose destination is#. Add your router’s link handling if needed. Connect actions to your services and show useful pending, empty or failure states where they apply. Hiding a link does not replace authorization in your application. - Make state ownership deliberate. Keep the layout mounted if its UI state should survive route changes. If desktop collapse must survive a reload, restore an initial or controlled value through
SidebarProvider. Its cookie write alone does not read and restore that preference for your app. - Replace placeholders before tuning the layout. Test your real pages and theme first, then adjust widths, spacing and overflow. Use semantic tokens so borders, backgrounds and interactive states continue to follow light and dark mode.
Start with Connect your application for the integration point, then use the data type reference to shape your inputs. Keep the copied folder together while changing its internals; there is no dependency on another sidebar variant’s installation.
Keep building
Source and customization
Use the checked-in Kamod implementation as your reference when adapting this variant. The showcase’s Code tab includes its supporting files, and the setup instructions explain where to place them and how to keep their imports intact. Before changing a helper, trace where it is used in the composition and check its inputs in the Props and data reference. This helps you adapt one part of the block without overlooking the files or behavior it depends on.
Source: Sidebar 4 on GitHub
Keep your local copy focused on the layout and interactions your app actually uses. Start with the data and content, then adjust composition and styling using the same semantic theme tokens.
Ready to integrate? Follow Add this block and the local usage example.
Design inspiration
Design reference
This variant follows the corresponding sidebar design in the shadcn/ui collection. Use the reference to compare the floating navigation surface and its spacing around expanded submenus. When adapting the Kamod version, start with your navigation hierarchy and page content, then follow the local composition example to connect the layout to your app.
Kamod expresses this layout with Preact components, its own sidebar behavior and semantic theme tokens. The copied variant keeps its composition, helpers and demo data together; your application supplies real destinations, content and actions.
Inspect the original variant’s source for the reference composition. The variant details above describe this implementation’s behavior and integration boundaries.
Use the original as a design reference. To install the Preact version shown here, follow Add this block and use this page’s download or Code tab. Its files and imports are prepared for Kamod.