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

@fikar/design-react

v1.4.0

Published

React components for the Fikar Ink design language. AppShell renders the canonical app shell from @fikar/design.

Readme

@fikar/design-react

React components for the Fikar Ink design language. It provides AppShell, NavItem, NavHeading, BrandLogo, AppLauncher, ThemeMenu, UserMenu, UserMenuItem, userInitials, SearchBox, SearchResults, FilterChip, EntityBadge, DetailPanel, DetailSection, ListRow, DaySeparator, StatusBadge, RelativeTime, formatRelative, formatExact, useShortcut and useAppShell. AppShell renders the canonical app shell from @fikar/design (recipes/shell.html), or the no-sidebar shell (recipes/shell-no-sidebar.html) with sidebar={false}, and owns the drawer, the desktop collapse and the rail tooltips.

The package ships no CSS. All styling comes from the class names in @fikar/design/components.css, so import that too. It releases at the same version as @fikar/design. What a version number promises, and how things are deprecated and removed, is in the "Versioning" and "Retiring something" sections of the root README (@fikar/design).

Peer ranges: @fikar/design >=1.0.0 <2 (optional, because this package publishes after the CSS package), react and react-dom ^18.3.0, @radix-ui/react-tooltip >=1.1.6 <2.

npm install @fikar/design-react @fikar/design @radix-ui/react-tooltip react react-dom
@import '@fikar/design/tokens.css';
@import '@fikar/design/components.css';
import { AppShell, NavHeading, NavItem } from '@fikar/design-react';
import { Link } from 'react-router-dom';

<AppShell
  brand={<img src={logo} alt="" />}
  brandName="FIKAR"
  nav={
    <>
      <NavHeading>Workspace</NavHeading>
      <NavItem component={Link} to="/" icon={<HomeIcon />} label="Home" active={pathname === '/'} />
      <NavItem component={Link} to="/settings" icon={<GearIcon />} label="Settings" badge="New" active={pathname === '/settings'} />
    </>
  }
  footer={<AccountBlock />}
  headerActions={<><AppLauncher apps={apps} currentId="platform" /><ThemeMenu value={theme} onChange={setTheme} /><UserMenu email={user.email} signOut={{ href: signOutUrl }} /></>}
>
  <Outlet />
</AppShell>

API

AppShell props: brand, brandName, navLabel (default "Main"), nav, navRail, navScroll, footer, headerStart, headerActions, children, fill (default false), sidebar (default true), collapsed, defaultCollapsed, onCollapsedChange.

The props are a union on sidebar. With the sidebar (the default) nav is required. With sidebar={false} the shell is a top bar and the content, and nav, navRail, navScroll, footer, navLabel, collapsed, defaultCollapsed and onCollapsedChange are never, so passing one is a type error. sidebar must be the literal true or false. In that mode the component reads and writes no storage, renders no drawer, and useAppShell() returns collapsed: false, drawerOpen: false, isRail: false with setters that do nothing. headerStart is worth using there: it sits between the brand and the cluster, and scrolls sideways inside itself when the bar is short of room, so the page does not widen and no link is lost.

<AppShell sidebar={false} brand={<BrandLogo lightSrc={light} darkSrc={dark} />} brandName="FIKAR" headerStart={<AdminLinks />} headerActions={<Cluster />}>
  <Outlet />
</AppShell>

footer is optional. Without it AppShell renders no .side-foot, so there is no bare divider above the collapse control. fill makes the shell one viewport tall at every width with a padless content column, for a page that scrolls inside itself (a conversation with a docked composer).

BrandLogo props: lightSrc, darkSrc (both required strings), alt (default "", given to both images) and height (number of px, inline style on both, absent by default so the package's 18px applies). It renders <img class="logo-light"> and <img class="logo-dark">; the package CSS shows the one that matches the theme (.dark or [data-theme='dark'] on an ancestor), and the classes only take effect inside .brand, so use it in the brand slot. brand itself stays a free slot: if you render your own logo, put logo-light and logo-dark on the two elements, <img> or inline <svg>. The old wrapper spans are not needed.

NavItem props: label, icon, badge, active, variant ('default' | 'back', default 'default'), component (default a), plus every prop the component accepts except className and children. variant="back" adds nav-item-back, the quieter link that leads out of this surface back to where the person came from; put it first. There is no className passthrough on purpose (KAN-311). It always renders a plain string className. Pass the router's Link as component and compute active in the app; NavLink manages its own class and aria-current, which fights the prop. A click closes the drawer.

NavHeading takes children and renders a group heading between nav items.

useAppShell() returns { collapsed, setCollapsed, drawerOpen, setDrawerOpen, isRail } for content inside the shell. isRail is true only while the rail is showing (collapsed and at least 1024px wide). brandName is separate from brand because the wordmark must sit inside .brand for the rail to hide it. headerStart fills the top bar left of the cluster, and navScroll makes a long nav scroll inside the sidebar.

The collapsed choice is stored in localStorage under fikar.shell.collapsed ("1" collapsed, "0" or absent open) unless you control it with collapsed. @fikar/design/shell.js writes the same values since 0.8.0.

Also new in 0.8.0 in the CSS, no React API needed: .rail-hidden and .rail-only for content that shows only open or only in the rail (.rail-hidden also leaves the tab order and the accessibility tree, so a list of links can go in it), and a fix that keeps a closed drawer out of the tab order. Upgrading from 0.7: the footer identity rule now matches direct children of .meta, so a plan pill in a nested span no longer needs a forced colour; the top bar and main area may shrink below their content; and an omitted footer renders no .side-foot. Full guide: the "React apps" section of the @fikar/design README.

Theme menu (since 1.2.0)

ThemeMenu is the sun or moon button and the panel of Light, Dark and System, for the second slot of the shell cluster. It renders recipes/theme-menu.html and needs @fikar/design 1.2.0 or later for its CSS, so install both at the same version. It keeps no state and stores nothing. The app passes the theme it has and a handler, and applies and saves the choice in its own way.

import { ThemeMenu } from '@fikar/design-react';

<ThemeMenu value={theme} onChange={(next) => { applyTheme(next); saveTheme(next); }} />

value is 'light', 'dark' or 'system', and the chosen row follows it. onChange is called with the row the person chose, unless it is the one already chosen. The sun or moon on the button comes from the theme on the root (.dark or [data-theme='dark']) in the CSS, so it is right on first paint and the component takes no theme for it. It opens on click and closes on Escape, on a press outside and on choosing a row, and the arrow keys move between the rows. The markup and behaviour are documented under "Theme menu" in the @fikar/design README.

User menu (since 1.1.0)

UserMenu is the avatar and account panel for the last slot of the shell cluster. It renders recipes/user-menu.html and needs @fikar/design 1.1.0 or later for its CSS, so install both at the same version. It opens on click and closes on Escape, on a press outside and on choosing a row, with no extra dependency.

import { UserMenu, UserMenuItem } from '@fikar/design-react';
import { Link } from 'react-router-dom';

<UserMenu
  name={user.name}
  email={user.email}
  avatarUrl={user.avatarUrl}
  accountSettings={{ component: Link, to: '/account' }}
  signOut={{ onSelect: () => { clearLocalState(); signOut(); } }}
>
  <UserMenuItem component={Link} to="/workspace">Workspace settings</UserMenuItem>
</UserMenu>

signOut takes { href } or { onSelect }. Leave out accountSettings to omit that row. userInitials(name, email) is the rule for the initials. The props, the markup and the behaviour are documented under "User menu" in the @fikar/design README.

App launcher (since 1.2.0)

AppLauncher is the grid button and app list for the first slot of the shell cluster. It renders recipes/launcher.html and needs @fikar/design 1.2.0 or later for the focus ring on its button, so install both at the same version. It opens on click and closes on Escape, on a press outside and on choosing an app, with no extra dependency. It fetches nothing, and it renders nothing when apps is empty.

import { AppLauncher } from '@fikar/design-react';

<AppLauncher
  apps={[
    { id: 'chat', name: 'Chat', url: 'https://chat.fikar.ai', hint: "Ask across your organization's memory" },
    { id: 'platform', name: 'Platform', url: 'https://platform.fikar.ai' },
  ]}
  currentId="chat"
/>

Each app has id, name, url and an optional hint. The app whose id is currentId gets .current and aria-current="page". The rows are plain links, because they leave the app. The props, the markup and the behaviour are documented under "App launcher recipe" in the @fikar/design README.

Search

SearchBox (a controlled search input with an icon, a clear button and a shortcut hint, in a 'bar' or 'panel' size), SearchResults (the typeahead listbox, which hears ArrowDown, ArrowUp, Enter and Escape on the input), FilterChip (a toggle pill with pressed and onToggle), EntityBadge (type is 'PERSON', 'ORGANIZATION', 'EVENT' or 'GEO') and useShortcut(keys, handler) ('/' and 'mod+k', the React counterpart of what shell.js binds). Each renders a recipe from @fikar/design (search.html, search-results.html, filter-chip.html, entity-badge.html) and adds no styling of its own. SearchBox forwards its ref to the input and never renders data-fk-search, so the app registers the shortcut with useShortcut. The props, an example and the drift check rule are in the root README under "Search".

Detail panel, list rows, status badges and relative time

DetailPanel (a type line with a dot, a serif title, a description and an optional close button) with DetailSection (a heading over rows or chips), ListRow (a title and a muted line, a button by default and a link with component) with DaySeparator, StatusBadge (status is 'success', 'warning', 'destructive' or 'muted', and the word is the children) and RelativeTime (a <time> that says "4 h ago" and keeps the exact time in its title, refreshing itself while mounted). formatRelative(value, now?) and formatExact(value, now?) are the same wording as FikarShell.formatRelative in shell.js. Each component renders a recipe from @fikar/design (detail-panel.html, list-row.html, status-badge.html, time.html) and adds no styling of its own. The props, the wording rules, the placement of the panel and what each app changes to adopt them are in the root README under "Detail panel, list row, status badge and relative time".