npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quanticjs/react-layouts

v8.2.0

Published

Application shell & layout components for QuanticJS — AppShell, Sidebar, TopBar, UserMenu

Downloads

1,093

Readme

@quanticjs/react-layouts

Application shell for QuanticJS apps — sidebar, top bar, mobile drawer, and user menu, driven by a nav config instead of hand-rolled chrome.

  • AppShell — composition root: persistent sidebar on lg+ with collapse-to-icons (persisted to localStorage), overlay drawer below lg (focus-trapped, Escape/backdrop close), skip-to-content link, <main> landmark.
  • Sidebar — renders a NavItem[] config with section headers, icons, one nesting level, and permission/role gating via Can from @quanticjs/react-core.
  • TopBarstart / actions slots plus a built-in UserMenu (session name from useAuth, logout via useLogout, custom entries, full keyboard support).
  • useSidebarState — read/control collapse and drawer state from app code.
  • Router-agnostic via renderLink / isActive. No state-management dependency (useSyncExternalStore internally). Styled exclusively with @quanticjs/tailwind-preset semantic tokens, so dark mode works automatically.

Install

pnpm add @quanticjs/react-layouts @quanticjs/react-ui @quanticjs/react-core

Requires @quanticjs/tailwind-preset >= 8 in the consuming app's CSS build — components render with v8 token utilities (shadow-* tiers, z-(--z-*), animate-*) that compile to nothing on older presets. See docs/MIGRATION-8.md.

@quanticjs/react-core powers permission gating and the user menu. Without a <QuanticProvider> ancestor the shell still renders — gated nav items and the session menu are simply hidden (a one-time warning logs in dev builds).

Usage with react-router

import { AppShell, type NavItem } from '@quanticjs/react-layouts';
import { Link, useLocation } from 'react-router-dom';
import { Home, Settings, Shield } from 'lucide-react';

const nav: NavItem[] = [
  { label: 'Dashboard', href: '/', icon: <Home /> },
  {
    section: 'Administration',
    label: 'Users',
    href: '/admin/users',
    icon: <Shield />,
    permission: 'users:manage',
  },
  {
    section: 'Administration',
    label: 'Settings',
    href: '/admin/settings',
    icon: <Settings />,
    role: 'admin',
    items: [
      { label: 'General', href: '/admin/settings/general' },
      { label: 'Branding', href: '/admin/settings/branding' },
    ],
  },
];

export function Layout({ children }: { children: React.ReactNode }) {
  const { pathname } = useLocation();
  return (
    <AppShell
      nav={nav}
      renderLink={(item, props) => (
        <Link to={item.href} {...props}>
          {props.children}
        </Link>
      )}
      isActive={(href) => pathname === href}
      topBar={{
        start: <h1 className="text-sm font-semibold">Delivery Hub</h1>,
        userMenu: {
          menuItems: [{ label: 'Profile', onSelect: () => navigate('/profile') }],
        },
      }}
    >
      {children}
    </AppShell>
  );
}

Usage with Next.js (App Router)

'use client';

import { AppShell, type NavItem } from '@quanticjs/react-layouts';
import Link from 'next/link';
import { usePathname } from 'next/navigation';

const nav: NavItem[] = [
  { label: 'Dashboard', href: '/' },
  { label: 'Reports', href: '/reports', permission: 'reports:read' },
];

export function Shell({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  return (
    <AppShell
      nav={nav}
      renderLink={(item, props) => (
        <Link href={item.href} className={props.className}>
          {props.children}
        </Link>
      )}
      isActive={(href) => pathname === href}
    >
      {children}
    </AppShell>
  );
}

AppShell is SSR-safe: the first render always uses the default expanded sidebar (no localStorage read), then syncs the persisted state after mount — no hydration mismatch.

Brand, nav badges, search & user subtitle

The shell renders a full dashboard chrome out of the box — a sidebar brand header, count badges on nav items, a top-bar search slot with an optional divider, and a subtitle under the user's name:

<AppShell
  nav={[
    { label: 'Dashboard', href: '/' },
    { label: 'Applications', href: '/apps', badge: 4 }, // count pill (dot when collapsed)
    { label: 'Support', href: '/support', badge: 2 },
  ]}
  renderLink={renderLink}
  brand={<Brand />}            // logo + wordmark (sidebar header)
  brandCollapsed={<LogoOnly />} // shown when the sidebar collapses to icons
  topBar={{
    start: <Breadcrumb items={[{ label: 'Portal', href: '/' }, { label: 'Dashboard' }]} />,
    search: <SearchField />,    // right cluster, before actions
    actions: <NotificationCenter />,
    showUserDivider: true,      // vertical rule before the user menu
    userMenu: { subtitle: 'Enterprise Client' }, // secondary line under the name
  }}
>
  {children}
</AppShell>
  • NavItem.badge renders a right-aligned count pill (a small dot when the sidebar is collapsed; the count is kept in the item's accessible name).
  • brand / brandCollapsed render in a header band above the nav.
  • topBar.search sits in the right cluster; showUserDivider adds the divider.
  • UserMenu uses Avatar (initials + image fallback) from @quanticjs/react-ui and shows subtitle under the name.
  • Build the page body with StatCard, Progress, Breadcrumb, and StatusBadge from @quanticjs/react-ui. The brand color is your app's primary (set via @quanticjs/tailwind-preset) — the shell ships brand-neutral.

Adding the notification bell

AppShell is notification-agnostic by design — it has no dependency on the notification engine. Mount the bell from @quanticjs/notification-ui in the topBar.actions slot, and wrap the shell in a NotificationProvider so the bell reads the app's appId and opens the realtime socket. The provider must sit above AppShell (or at least above the bell):

import { AppShell } from '@quanticjs/react-layouts';
import { NotificationProvider, NotificationCenter } from '@quanticjs/notification-ui';

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    // appId = this app's slug in the notification engine's application registry.
    // Omit appId on a shell/portal to get the unified cross-app inbox.
    <NotificationProvider appId="delivery-hub">
      <AppShell
        nav={nav}
        renderLink={renderLink}
        topBar={{
          start: <h1 className="text-sm font-semibold">Delivery Hub</h1>,
          actions: <NotificationCenter />,
          userMenu: { menuItems: [{ label: 'Profile', onSelect: () => navigate('/profile') }] },
        }}
      >
        {children}
      </AppShell>
    </NotificationProvider>
  );
}

The actions slot takes any ReactNode, so you can place other controls (theme toggle, etc.) alongside the bell. See @quanticjs/notification-ui for the provider options, the engine endpoint contract, and the BFF proxy requirement.

API

AppShellProps

| Prop | Type | Notes | |---|---|---| | nav | NavItem[] | Required. | | renderLink | (item, { className, children }) => ReactNode | Required router adapter. | | isActive | (href: string) => boolean | Active item styling. | | topBar | { start?, actions?, userMenu? } | userMenu: false hides the built-in menu. | | labels | Partial<ShellLabels> | Override any built-in string (i18n). | | storageKey | string | Collapse persistence key. Default quantic.sidebar. | | contentClassName | string | Override <main> classes. Default gutter is p-4 sm:p-6; pass p-0 for full-bleed pages. |

NavItem

label, href, icon?, permission?, role?, section? (group header for consecutive items), items? (one nesting level — deeper levels are flattened with a dev warning).

Items with permission/role render inside Can; a section header is hidden automatically when every item in the section is hidden.

Labels / i18n

All built-in strings are overridable, either per component:

<AppShell labels={{ logout: 'Abmelden', skipToContent: 'Zum Inhalt springen' }} … />

…or app-wide via the TranslationProvider from @quanticjs/react-ui — this package registers the layouts namespace (LayoutsTranslations), and every shell component resolves each label with the precedence explicit labels prop > provider catalog > English default:

import { TranslationProvider } from '@quanticjs/react-ui';

<TranslationProvider
  translations={{ layouts: { shell: { logout: 'Abmelden', navigation: 'Hauptnavigation' } } }}
>
  <AppShell … />
</TranslationProvider>

useShellLabels(overrides?) is exported for consumers building custom shell parts that should follow the same resolution.

Exports

AppShell, type AppShellProps
Sidebar, type SidebarProps, type NavItem, type RenderLink
TopBar, type TopBarProps
UserMenu, type UserMenuProps, type UserMenuItem
useSidebarState
defaultLabels, useShellLabels, type ShellLabels, type LayoutsTranslations

RTL & reduced motion

All positioned chrome — the skip link, sidebar border, nesting indent, mobile drawer, and user-menu dropdown — uses Tailwind logical properties (start-*, ps-*, border-e, text-start). Set dir="rtl" on <html> (or any ancestor) and the shell mirrors automatically; no props or providers involved. Hover/expand transitions respect prefers-reduced-motion via the global block in @quanticjs/tailwind-preset's theme.css.