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

@hilum/app-shell

v4.7.5

Published

Composed product-app layouts — AppShell, AppSidebar, AppHeader, PageHeader, DetailScreen, SettingsScreen, SignInScreen

Readme

@hilum/app-shell

Composed product-app layouts — app frame, sidebar navigation, top bar, page headers, detail/settings screens. Built on @hilum/ui primitives. Used by every Hilum product app (CRM, admin, dashboard, etc.) to ensure structural consistency.

import {
  AppCommandButton,
  AppCommandPalette,
  AppHeader,
  AppMobileNav,
  AppShell,
  AppSidebar,
} from "@hilum/app-shell";
import Link from "next/link";

<AppShell
  linkComponent={Link}
  sidebar={<AppSidebar sections={sections} user={currentUser} className="hidden md:flex" />}
  banner={<AppMobileNav brand="Hilum Shop" sections={sections} user={currentUser} />}
  header={
    <AppHeader breadcrumbs={[{ label: "Products", href: "/products" }, { label: "T-shirt" }]} />
  }
  search={<AppCommandButton />}
  loading={isNavigating}
>
  <AppCommandPalette sections={sections} onNavigate={router.push} />
  {children}
</AppShell>;

sections is a NavSection[]:

const sections: NavSection[] = [
  {
    label: "Store",
    items: [
      { label: "Home", href: "/", icon: HomeIcon, active: pathname === "/" },
      {
        label: "Products",
        href: "/products",
        icon: PackageIcon,
        children: [
          {
            label: "Collections",
            href: "/products/collections",
            active: pathname === "/products/collections",
          },
          { label: "Inventory", href: "/products/inventory" },
        ],
      },
      { label: "Analytics", href: "/analytics", disabled: true },
    ],
  },
];

Routing

@hilum/app-shell is router-agnostic. Pass your router's link component via <AppShell linkComponent={Link}>. Active state is caller-computed — pass active: boolean per nav item using your router's pathname.

The link context lives in @hilum/ui (LinkProvider, useLink, LinkComponent, LinkComponentProps) and is re-exported here, so one provider drives links in both packages — @hilum/ui components rendered inside <AppShell linkComponent> navigate client-side too. You can also mount <LinkProvider value={Link}> yourself above the app.

The app frame (AppShell / AppShellStacked)

There is no separate AppFrame component: the two shells are the frame and share the same frame props (AppFrameProps). Pick AppShell for sidebar layouts and AppShellStacked for top-nav layouts.

| Prop | Default | What it does | | --------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | linkComponent | plain <a> | Router link used by every Hilum link (see Routing). | | sidebar | — | AppShell only. Navigation column (<AppSidebar>). | | header | — | AppShell only. Top bar (<AppHeader>). | | banner | — | Content above the header (AppShell) or below the navbar (AppShellStacked) — status banners, <AppMobileNav>. | | search | — | Top-bar search slot. <AppHeader> / <Navbar> render it automatically (their own search prop wins). | | loading | false | Thin indeterminate progress bar at the top of the frame; sets aria-busy on <main>. Static under prefers-reduced-motion. | | loadingLabel | "Loading" | Accessible name of the progress bar. | | toaster | true | Mounts @hilum/ui's <Toaster> once. Pass ToasterProps to configure, or false if the app already mounts one. Fire toasts with toast() from @hilum/ui. | | main | true | Wraps children in <main id={mainId} tabIndex={-1}>. Pass false to render your own <main> (give it the same id). | | mainId | "main-content" | Id of the main region / skip-link target. | | mainClassName | — | Classes for the generated <main>. | | skipLink | true | Renders a "Skip to content" link that becomes visible on focus. Pass a node to change its text, false to omit. | | headerHeight | "4rem" | Sets --hilum-header-height on the frame. AppHeader and Navbar size themselves from it; sticky surfaces such as ContextualSaveBar can offset with top-[var(--hilum-header-height,0px)]. |

The frame fills the dynamic viewport (h-dvh), so it doesn't hide behind mobile browser toolbars. Components inside the frame can read { search, mainId } with useAppFrame().

Migrating from the children-only composition. Earlier versions expected <AppSidebar>, <AppHeader> and your own <main> as children. AppShell now wraps children in <main>, so either move the sidebar/header into the sidebar/header props (recommended), or keep the old markup and pass main={false} plus id="main-content" on your <main>.

SkipLink and AppLoadingBar are exported for custom frames.

Navigation

  • AppSidebar — sectioned navigation wrapped in <nav aria-label={navLabel}> (default "Main"). Works standalone (renders an <aside>) or inside @hilum/ui's <Sidebar> (collapsible, collapsed for the icon rail).
  • Nested items — NavItem.children render as a collapsible sub-list with a toggle button (aria-expanded / aria-controls). A parent auto-expands whenever one of its descendants is active (also after client-side navigation); defaultExpanded sets the initial state otherwise.
  • Disabled items — disabled: true renders a non-focusable <span role="link" aria-disabled="true"> (no href) in every navigation component.
  • AppMobileNav — mobile (below md) top bar with two variants:
    • variant="tabs" — horizontally scrolling tab strip of top-level items.
    • variant="drawer" — hamburger button opening a sheet with the full sectioned + nested navigation (<AppNavTree>), closing on navigate.
    • Default: drawer when there are more than 5 top-level items or any item has children, otherwise tabs.
  • Navbar — top bar for AppShellStacked / marketing pages. Below md its links move into a menu sheet (mobileMenu, menuLabel, menuTitle); navLabel names the landmark.
  • AppNavTree — the full nested nav list used by the drawers; drop it into any custom sheet.
  • AppCommandPalette — ⌘K palette; includes nested nav items.
  • Helpers: flattenNavSections, flattenNavItems, isNavItemActive.

Breadcrumbs

<AppHeader breadcrumbs> renders <nav aria-label="Breadcrumb"><ol><li>…, with the last crumb marked aria-current="page" (never a link).

PageHeader

Polaris Page-style header:

<PageHeader
  title="Summer sale"
  backAction={{ label: "Collections", href: "/collections" }}
  titleMetadata={<StatusBadge status="active" />}
  description="24 products"
  primaryAction={{ label: "Save", onAction: save, loading: saving }}
  secondaryActions={[
    { label: "Duplicate", onAction: duplicate },
    { label: "Preview", href: "/preview" },
    { label: "Delete", destructive: true, onAction: remove },
  ]}
/>
  • primaryAction / secondaryActions (PageHeaderAction: label, href or onAction, icon, disabled, loading, destructive, accessibilityLabel).
  • Secondary actions show inline on wide headers (up to maxVisibleSecondaryActions, default 3; the rest overflow) and collapse into a "More actions" menu (moreActionsLabel) when the header is narrow. Sizing uses container queries on the header (@container/page-header), not the viewport, so it adapts inside split panes and modals.
  • backAction — icon-only back button beside the title ("Back to {label}"). The text-style back link is still supported.
  • titleMetadata (alias of badges) — inline metadata after the title; meta — metadata row below.
  • actions still accepts free-form nodes (rendered after the structured actions). PageHeaderActions no longer relies on app-specific classes (.dashboard-action-*) or viewport widths; give a child data-span="full" to keep it full-width in the stacked layout.

Other screens

DetailScreen, SettingsScreen, SignInScreen (renders its form inside <main id="main-content">), SignInDecoration (the headline and icon highlights for SignInScreen decoration), AppAccountMenu (avatar account menu for AppHeader actions, same contents as the AppSidebar user menu), AppStatusBanner, AppNotificationMenu.

RTL

Layout classes are logical (ms/me/ps/pe/start/end, text-start, border-s/border-e) and directional icons flip under dir="rtl".