Dashral Pro is on the wayGet 30% off at launch

Dashral

App shellPro

A whole app layout: drag the sidebar's edge to resize it or snap it to a rail, ⌘K to jump anywhere, favorites you drag to reorder, recent pages and a sliding highlight.

When to use

  • A whole app layout: a resizable sidebar that snaps to a rail, ⌘K to jump anywhere, favorites and recent pages.
  • Data-heavy apps people keep open all day, where layout and quick navigation matter.

When not to use

  • Simple dashboards: Dashboard sidebar with Dashboard header is less to wire.
  • Marketing pages and public sites.

Usage

App shell with your own data: every prop has the sample as its default, so pass only what you have.

example.tsx
import { AppShell } from "@/components/dashral/blocks/app-shell"

<AppShell
  pages={pages}
  boards={dashboards}
  current={pageId}
  onNavigate={(id) => router.push(`/${id}`)}
  favorites={favorites}
  onFavoritesChange={(ids) => api.user.saveFavorites(ids)}
  user={user}
  usage={{ label: "Storage", value: "7.2 of 10 GB", percent: 72 }}
>
  {(page) => <Page id={page.id} />}
</AppShell>

API reference

AppShell

A whole app shell: the sidebar, a header and the page. Drag the sidebar's edge to resize it — narrow enough and it snaps to a rail of icons; double-click the edge for the default width — or press [ to fold it. ⌘K (Ctrl+K) jumps to any page. Favorites reorder by dragging (or Alt+↑/↓), the star in the page header pins the page, Recent keeps what you visited, and a highlight slides to the current page. On phones the sidebar is a sheet. Your pages and dashboards, workspaces, user and usage card come in as props; the page you're on, the workspace and the favorites are controllable, each with its handler. children renders the page (the sample one without it).

PropTypeDefault
pagesShellItem[]sample
boardsShellItem[]

The second list, shown under Dashboards in the jump list; favorites and recent can hold either.

sample
currentstring

The page you're on, by id (the shell keeps it without it); "settings" is the account's settings.

—
onNavigate(id: string) => void—
favoritesstring[]

Pinned page ids, in order.

—
onFavoritesChange(ids: string[]) => void—
recentstring[]

The pages Recent starts with; it keeps what you visit after.

["okrs", "customers"]
workspacesstring[]sample
workspacestring—
onWorkspaceChange(workspace: string) => void—
user{ name: string; email: string; src?: string }sample
usage{ label: string; value: string; percent: number } | null

The meter above the account; null hides it.

sample
unreadboolean

The dot on the bell.

true
onAction(action: ShellAction) => void—
classNamestring

Classes for the shell; it fills the screen's height (h-svh), so set another height to place it in a page.

—
children(page: ShellItem) => React.ReactNode

The page for the current item; without it, a sample page that changes with each one.

—

type ShellItem

A page in the sidebar: an icon, or a coloured dot (a class like "bg-success"), and a count.

PropTypeDefault
idstring—
labelstring—
iconLucideIcon—
dotstring—
badgenumber—

type ShellAction

The buttons that don't navigate.

= "new-workspace" | "notifications"