A sidebar in a dialog. 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.

Interactive previewTry it before you copy it

Variant 13 of 16

Getting started

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. Download this variant and extract its sidebar-13 folder into src/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 outer sidebar-13/ folder: extract it once, rather than creating a second nested folder with the same name. The import examples assume src/App.tsx.

    Download block
    Install dependencies

    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-13/, and its imports already match the download. Keep the included license with your copy.

  2. 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/signals
  3. 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 { Sidebar13 } from "./components/blocks/sidebar-13";

    The @kamod-ch/blocks/sidebar/sidebar-13 path 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

Start with the complete preview composition, then adapt its local source to your app. The exported Sidebar13 takes no props; navigation, content and behavior are configured inside your copied files.

Think of this block as an editable starting layout. Rendering <Sidebar13 /> 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-13.tsx to see how the pieces fit together. Keep its provider and layout structure while replacing the parts you need. The Sidebar13 wrapper is your local page; the core Sidebar inside 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
Replace the placeholder panels inside the existing main. Retain the surrounding header and navigation. 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 Sidebar13.

// Replace the placeholder panels in sidebar-13.tsx.
<section class="p-4" aria-labelledby="page-title">
  <h1 id="page-title">Account settings</h1>
</section>

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 Sidebar13, 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 once in your page or route layout. It already includes its own SidebarProvider, so you do not need another provider around this example. This variant first shows a button that opens the settings dialog.

import { Sidebar13 } from "./components/blocks/sidebar-13";

export const App = () => <Sidebar13 />;

Your copied sidebar-13.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-13.tsx, keep DialogTitle and replace the demo panels.
<section aria-labelledby="account-settings">
  <h2 id="account-settings">Account settings</h2>
  <p>Place your application's settings form here.</p>
</section>

These are local edits, not props to pass to <Sidebar13 />. See Local props and data for the helpers this variant actually includes and their supported inputs.

Replace the placeholder panels inside the dialog’s existing main with your settings form. Keep DialogTitle for its accessible name and connect the navigation buttons to the panel your app should display.

  • Selection and actions. The first settings item is highlighted in the demo; derive that selection from your own state. Connect any search, account or form controls you keep to real application handlers.
  • 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

Sidebar13 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-13.tsx.

The signatures below come from the copied source files. Use the data type reference to inspect complete definitions and required fields. Optional callbacks do not imply that a backend is included. Select a table row’s type name to open its definition automatically. Use 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.TypeScript
Each field includes its type and integration behavior. The asterisk
marks required fields. Navigation helpers require their data; omitted optional fields use the defaults described below. The definitions retain the actual source’s optional markers and callback return types. Read each field together with its owning type: the same name can have a different purpose on another helper. A ? 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 [].
Local helper props and data fields
Prop / typeDescription
title
stringSettingsItem
Visible settings category label in the dialog’s navigation. In the supplied Sidebar13 example the first entry is always styled as active, so reordering entries moves the highlight but does not create working panel selection. Keep titles distinct and replace that demo selection rule with your own state when connecting real settings panels.
icon
ComponentChildrenSettingsItem
Renderable Preact content shown beside the settings label, for example a JSX element such as <SettingsIcon />. This differs from the icon-map key used by primary navigation and the component reference used by secondary links. Create the element in your settings data and use its props for any sizing adjustments. The icon itself does not implement panel switching.

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.

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.

SettingsItem
Data shape from data/settings-data.tsx. Supply real application values using the required and optional fields below.
Required fields
title, icon

Variant details

The Open settings trigger opens a core Dialog with a settings sidebar and content area. Keep its accessible DialogTitle even when visually hidden. Replace placeholder settings content and wire each destination to the relevant panel.

Edit sidebar-13.tsx for layout and data/ for example content. Each variant is an explicit composition; there is no configuration switch or dependency on another variant.

A closer look

A settings interface inside a dialog rather than a persistent application shell. The page starts with an Open settings button; the dialog combines a left-hand list of settings areas with a scrollable content region. This lets a focused configuration task appear over an existing page without replacing its surrounding application layout.

Where this layout adds value
Useful for a limited group of account or workspace settings that users visit briefly and then dismiss. The side navigation gives those settings an outline while the dialog preserves the idea of returning to the underlying task. It is less suitable for a large settings product with many independently shareable pages.
The tradeoff to consider
The navigation is hidden below 768px and no replacement selector is included. Desktop settings buttons are also not wired to change panels. A production dialog needs a mobile way to choose sections and a decision about saving, cancelling and unsaved edits before it can serve as a complete settings flow.

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 5
Provides persistent application navigation for settings that should behave as normal routed pages rather than an overlay task.
Sidebar 14
Places navigation on the right of a full page. It changes the layout's side, not its modality or settings behavior.

A core Dialog surrounds SidebarProvider. The inner Sidebar uses collapsible="none" and is hidden below the medium breakpoint; it is not a sheet within the dialog. A visually hidden DialogTitle names the overlay. The main region contains a Settings breadcrumb and a fixed-height, independently scrollable placeholder area.

In the downloaded folder, index.ts exports Sidebar13. Its sidebar-13.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.

DialogTrigger opens the overlay, and the core dialog handles its open/close interaction. The first settings row is styled active by its index, not by a selected settings-panel state. Clicking another row does not replace content. There is no form submission, validation or persistence attached to the placeholder panels.

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 isActive flag supplies styling; it is not a router. Where a helper initializes a disclosure with defaultOpen, 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.

The settings sidebar is hidden below 768px and does not become a sheet inside the dialog. Provide an alternative mobile settings selector before relying on those destinations.

This dialog composition uses a non-collapsible sidebar. The small-screen behavior comes from its visibility classes, not a separate navigation sheet. Keep the dialog opener mounted and the content scrollable while adding an alternative settings selector for narrower screens.

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.

Retain the accessible DialogTitle even if it remains visually hidden. Keep focus within the open dialog and return it on dismissal. Test long forms with zoom and the on-screen keyboard so required fields and save controls are not trapped below a fixed-height region.

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 main elements. Give distinct navigation regions meaningful labels when your adaptation contains more than one. The core provider also registers Ctrl/Cmd+B to 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.

Introduce a selected settings section, render its actual fields and provide an equivalent small-screen selector. Decide whether edits save immediately or require an explicit save action, and define what dismissal does with unsaved values. Keep the opener mounted so closing the dialog can restore focus predictably.

  1. Replace demo navigation. Supply real URLs: the shared stopNavigation helper 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.
  2. Make state ownership deliberate. Keep the layout mounted if its UI state should survive route changes. Keep settings values in application state if they must survive closing the dialog. Define whether reopening restores a draft or reloads saved values; an open dialog is not a persistence mechanism.
  3. 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

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.

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

This variant follows the corresponding sidebar design in the shadcn/ui collection. Use the reference to compare navigation and settings content inside a dialog. 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.