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

@ossy/design-system

v3.10.0

Published

Ossy's design system React component library

Readme

@ossy/design-system

React component library for the Ossy ecosystem — themable UI primitives, layout, forms, and shell extension hooks. Built for React 19+ with server-side rendering and CSS-variable theming from @ossy/themes.

This package is not a home for product-specific or marketing widgets. Domain UI lives in feature packages (for example @ossy/profile, @ossy/resumes, @ossy/booking).

What’s in the box

| Area | Examples | |------|----------| | Primitives | Button, Text, Input, InputTitle, Card, Alert, Badge, Tabs, … | | Layout | View, View.Item, Page, PageSection | | Forms | Form, FieldFactory, Fields, applyFieldChange, FormStatus, useFormContext, field slot keys | | Theme | Theme, useTheme (requires @ossy/themes) | | Shell extension | ComponentSlotsProvider, Slot, useSlot | | Icons | Icon — kebab-case names, lazy css.gg chunks |

See docs/SLOTS.md for the three different “slot” concepts and AUDIT.md for refactor history and open work.

Four-layer mental model

Use this stack when deciding which API to reach for:

  1. Tokens & theme — Install @ossy/themes, wrap the app in Theme, switch palettes with useTheme. Components read var(--*) tokens only at the global level.
  2. Layout primitivesView (and optionally Page / PageSection) for structure. Layout slots are the slot attribute on children (header, content, sidebar-primary, …).
  3. Shell & form extensionComponent slots: app export const slots in *.layout.jsx + <Slot />; schema UI via ADR 0006 metadata.id on *.component.jsx. Form fields: @ossy/design-system/input/{type}.
  4. Components — Buttons, inputs, feedback, display, navigation helpers.

Rule of thumb: layout regions ≠ injectable app components ≠ form field overrides.

Typography (Text)

Single component for body and headings. Set as for semantics (h1, label, p, …), variant for theme tokens under theme.text, and optional text / params for locale keys. InputTitle is a separate borderless input styled like a heading — use it as a form-field slot override for resource name editing, not as display typography.

Responsive type comes from the theme, not from Text props: @ossy/themes base.media['(max-width: 900px)'].text overrides heading/hero/logo sizes via createCss @media CSS variables. Keep body/default at 1rem so iOS does not zoom focused inputs.

Feedback (Alert)

Theme-aware callout for inline status. Tones come from CSS variables (--color-info, --color-accent for success, --color-warning, --color-danger); neutral uses surface/separator tokens so light and dark themes stay consistent.

| Prop | Purpose | |------|---------| | variant | neutral (default), info, success, warning, danger | | title | Optional uppercase eyebrow above the body | | icon | Optional leading React node (inline SVG or Icon) | | onDismiss | When set, renders an accessible dismiss control | | dismissLabel | aria-label for the dismiss control (default Dismiss) | | as | Root element (default div) | | role | Override a11y role (danger defaults to alert, others to status) |

import { Alert } from '@ossy/design-system'

<Alert variant="warning" title="Attention" onDismiss={() => setOpen(false)}>
  This action cannot be undone after 24 hours.
</Alert>

Status (Badge)

Compact pill for inline status. Variants share Alert’s semantic --color-* mapping (success--color-accent, warning--color-warning, …) via color-mix against --surface-base, so badges follow light/dark themes.

| Prop | Purpose | |------|---------| | variant | neutral (default), info, success, warning, danger | | size | s or m (default) | | label / children | Badge text |

import { Badge } from '@ossy/design-system'

<Badge variant="warning">Pending</Badge>

Installation

npm install @ossy/design-system @ossy/themes

Peer dependencies

  • react >= 19.0.0
  • react-dom >= 19.0.0
  • @ossy/themes — theme objects passed to Theme
  • markdown-to-jsx, react-syntax-highlighter — only if you use MarkdownViewer

Quick start

import { Text, Theme } from '@ossy/design-system'
import { CloudLight } from '@ossy/themes'

export default function App() {
  return (
    <Theme theme={CloudLight}>
      <YourApp />
    </Theme>
  )
}

Multiple themes with runtime switching:

import { Text, Theme } from '@ossy/design-system'
import { CloudLight, CloudDark } from '@ossy/themes'

<Theme
  theme={CloudLight}
  themes={{ light: CloudLight, dark: CloudDark }}
  defaultTheme="light"
>
  <YourApp />
</Theme>

Storybook

Component docs and MDX guides live in the ossy monorepo Storybook. Feature package UI is previewed in @ossy/app-test, not Storybook.

From the monorepo root (business/platform/ossy):

npm install   # if needed
npm start     # storybook dev -p 6006

Open in the browser:

  • Design System → Getting Startedpackages/design-system/docs/intro.mdx
  • Design System → Layout Guide and Slots — layout and injection docs (layout-guide.mdx, slots.mdx)
  • Design System → Principles, Theme Concepts, Patterns, Variants — other packages/design-system/docs/*.mdx
  • Design System → Base / …*.stories.jsx next to components

Static build: npm run build:storybook.

Storybook resolves @ossy/design-system from source (src/index.js), so you do not need lerna run build before npm start.

Layout guide

When to use what

| Need | Use | |------|-----| | Flex/grid, gaps, surfaces, app chrome grid | View with a layout preset and data-region children | | Standard in-app page body (scroll, header, slot spacing) | Page — optional maxWidth, built-in header via page.* slots | | Centered content band with max-width only | PageSection (marketing heroes, standalone sections) | | Bordered vertical/horizontal list of panels | View with stack, horizontal, bordered, and View.Item | | Injectable header/sidebar/toolbar from packages | <Slot view="…" region="…" /> + *.component.jsx — see docs/SLOTS.md |

View layout presets

View is the primary layout primitive. Set layout to a preset (page, sidebar, off-center, column, row, …) and assign children with data-region="header", data-region="content", etc. Storybook Design System → Base → View shows each preset.

layout="header" — title row (leading + optional far), optional description and children rows below. The default grid is a single row ("leading far"); :has([data-header-slot="…"]) expands to two or three rows when description and/or children slots are present, so row gap is not applied between empty tracks. Used by ContentHeader and AppHeader via HeaderLayout.

Page and PageSection

Page is the standard in-app page body inside the shell content region. It renders a single root View (default layout="page") with registered slots for each layout region. Built-in title / description / near / far props feed the page.header slot fallback (ContentHeader); override the region via ComponentSlotsProvider or the header prop. Unslotted children land in page.content. Children with region or data-region props become fallbacks for the matching page slot.

Props:

| Prop | Purpose | |------|---------| | title, description, near, far, … | Passed to page.header slot (fallback: built-in ContentHeader) | | header | Custom header node for page.header fallback; when set, built-in header props are ignored | | maxWidth | Wraps content in PageSection for a centered max-width band (s, m, l, xl, …) | | inset | Default s (minimal edge padding on content); none for full-bleed; or any View inset token | | scroll | false (default): page grows with content; the shell scrolls (@ossy/app/layout/default). true: page fills a height-locked shell <main> (e.g. @ossy/app/layout/workspace) and page.content scrolls (or nested panels via contentStyle). | | contentStyle | Extra styles on page.content (e.g. { overflow: 'hidden' } so child panels own scrolling, as on Storage) | | layout | page (default) or columnpage uses View layout="page" grid regions | | surface, gap | Passed through to the root View (gap applies to content column) |

Page layout region slot keys:

| Key | Region | |-----|--------| | page.header | Top title row | | page.content | Main body (scrolls when scroll is true) | | page.sidebar-primary | Left rail | | page.sidebar-secondary | Right rail | | page.footer | Bottom bar |

import { Page, Button, ComponentSlotsProvider } from '@ossy/design-system'

<Page
  title="tasks.home.title"
  description="tasks.home.description"
  near={<Tags tags={['Beta']} size="s" />}
  far={<Button variant="cta" label="design-system.add" />}
>
  {children}
</Page>

// Override page.header for a route or feature:
<ComponentSlotsProvider slots={{ 'page.header': MyPageHeader }}>
  <Page title="…">…</Page>
</ComponentSlotsProvider>

For a fully custom page header, pass header={<ContentHeader … />} or any node as the page.header fallback. Use ContentHeader as a body child for section intros within the page.

ContentHeader and AppHeader

Both use HeaderLayout (View layout="header") and share most props:

| Prop | Purpose | |------|---------| | title | i18n key (string) or custom title node (ReactNode) | | titleParams, titleAs, titleVariant | Used when title is a string | | description, descriptionParams, … | Lead paragraph below the title row | | lead | Custom lead node (overrides description) | | near | Slot beside the title (tags, status badges, etc.) | | far | Slot on the right (CTA buttons, toolbar actions) |

  • ContentHeader — page title row inside Page (data-component="content-header", default inset="list-row"). Page uses this as the built-in page.header fallback.
  • AppHeader — app shell top bar (data-component="app-header", default inset="m"). Register on app:header; typically only the first header row (logo + actions).
import { ContentHeader, AppHeader, Tags, Button } from '@ossy/design-system'

<ContentHeader
  title="tasks.home.title"
  near={<Tags tags={['Beta']} size="s" />}
  far={<Button variant="cta" label="design-system.add" />}
/>

<AppHeader
  title={<Text variant="heading-tertiary">Workspace</Text>}
  far={<Button variant="link" prefix="profile" label="Profile" />}
/>

PageSection is a max-width wrapper around arbitrary content — use for marketing heroes (HeroCover), sales blocks, or when you need a centered band without the full page chrome. For normal app pages, prefer Page with maxWidth instead of hand-rolling View + padding.

Shell canvas (full viewport behind <main>) uses View surface="base", not Page.

Stack → View (migration)

Stack and Stack.Item were removed. Use View with stack mode:

Before

import { Text, Stack } from '@ossy/design-system'

<Stack horizontal bordered>
  <Stack.Item fill>…</Stack.Item>
  <Stack.Item>…</Stack.Item>
</Stack>

After

import { Text, View } from '@ossy/design-system'

<View stack horizontal bordered>
  <View.Item fill>…</View.Item>
  <View.Item>…</View.Item>
</View>
  • stack — enables stack item styling and borders
  • horizontal — row direction (default column)
  • bordered — separators between items
  • View.Item — same as former Stack.Item (fill prop supported)

Icons (migration)

Legacy Material Icon and Icon2 are consolidated into a single Icon export.

| Before | After | |--------|--------| | Icon2 with name="arrow-right" | Icon with name="arrow-right" | | Legacy Icon with PascalCase / Material names | Icon with kebab-case css.gg name (see Storybook Design System → Base → Icon) | | icon= prop on some internals | Prefer name= (icon still accepted as alias) |

Icons load lazily per name. Unknown names log a warning and render empty.

import { Text, Icon } from '@ossy/design-system'

<Icon name="check" size="m" variant="primary" />

Domain widgets (moved out)

These are no longer exported from @ossy/design-system:

| Former export | New home | |---------------|----------| | Profile | @ossy/design-system | | ResumeExperience, ResumeView | @ossy/resumes | | sections/* (Hero, marketing blocks, …) | Consumer feature packages or local app code — sections/ removed from design-system |

Install the feature package that owns the domain, or copy patterns using View + primitives.

Platform integration

  • Pages*.page.jsx primitives; use design-system for UI inside pages. PRIMITIVES.md
  • App chrome — app export const slots in *.layout.jsx maps app:* to component ids; platform sets app:content to the current page. docs/SLOTS.md, SHELL-SPEC.md
  • Resource / schema UI*.component.jsx with metadata.id = @ossy/…/view/…, @ossy/…/form/…, or @ossy/design-system/input/…

Deprecations and removed exports

Removed (breaking)

  • Stack, Stack.Item — use View + stack / View.Item
  • Legacy Material Icon — use Icon with kebab-case name
  • Icon2 — renamed to Icon (same API)
  • ResumeExperience, ResumeView — use @ossy/resumes
  • sections/* exports
  • TemplateForm — use <Form><FieldFactory /></Form>
  • Title — use Text with as + heading variants (heading-primary, heading-secondary, …)
  • EditFields, ResourceTemplateFields — use Fields
  • applyResourceTemplateFieldChange — use applyFieldChange
  • ComponentsProvider, useComponentSlot — use ComponentSlotsProvider, useSlot
  • resourceSlot, RESOURCE_SLOT_PREFIX, normalizeResourceTypeKey — use viewComponentId / formComponentId from @ossy/schema

Further reading

License

MIT