Skip to main content

Sidebar

br.sidebar creates a persistent left rail that renders on every page. It's a container — anything you can do inside the root br (write, inputs, selects, charts) you can do inside the sidebar.

Because the sidebar is shared across all pages, filter state set once stays visible as the user navigates. This makes it the natural home for global controls: search boxes, region pickers, date-range selectors, or any input that should survive page changes.

The sidebar opens as a slide-in panel with a backdrop overlay. Clicking the backdrop or the ✕ button closes it; a tab on the left edge lets the user reopen it.

Basic usage

const sidebar = br.sidebar({});
sidebar.write({ body: '## Filters' });
const region = sidebar.select({
label: 'Region',
options: [
{ value: 'eu', label: 'EU' },
{ value: 'us', label: 'US' },
],
});

Nesting inputs

The sidebar is a full container — nest any components inside it:

const sidebar = br.sidebar({});

sidebar.write({ body: '## Controls' });

const search = sidebar.textInput({
label: 'Search',
placeholder: 'Type to filter…',
});

const dark = sidebar.toggle({ label: 'Dark mode' });

const count = sidebar.numberInput({
label: 'Items per page',
defaultValue: 25,
min: 5,
max: 100,
});

Combining with pages

The sidebar renders on every page. Use br.page for the main content and let the sidebar provide shared controls:

run((br) => {
const sidebar = br.sidebar({});
sidebar.write({ body: '## Navigation' });
sidebar.toggle({ label: 'Show details' });

const home = br.page({ path: '/' });
home.write({ body: '# Home' });

const settings = br.page({ path: '/settings' });
settings.write({ body: '# Settings' });
});

The toggle state set on the sidebar page is visible from both routes.

Conditional content per route

run passes a second argument with currentPath — the pathname that triggered this execution. Use it to show different sidebar content on different pages without re-declaring the sidebar:

run((br, { currentPath }) => {
const sidebar = br.sidebar({});
sidebar.link({ label: '🏠 Home', href: '/' });
sidebar.link({ label: '⚙️ Settings', href: '/settings' });

if (currentPath === '/settings') {
sidebar.write({ body: '---' });
sidebar.write({ body: '### Settings' });
sidebar.toggle({ label: 'Email notifications' });
sidebar.toggle({ label: 'Dark mode' });
}

br.page({ path: '/settings' }).write({ body: '# Settings' });
});

currentPath reflects the URL that triggered the current run — navigation fires a new run, so currentPath is always up to date.

Multiple sidebars

Calling br.sidebar() more than once creates multiple sidebar instances. Each one portals to the same overlay layer, so only the last-rendered sidebar will be visually on top. In practice you should call br.sidebar() once at the top of your script and share it across pages.

Try it