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

@cratis/components

v2.3.0

Published

A collection of React components for building modern applications with Cratis.

Downloads

1,474

Readme

Cratis Components

A collection of React components for building modern applications with Cratis.

Requirements

Minimum Versions

  • TypeScript: 4.7+
  • React: 18.0+ or 19.0+
  • Node.js: 16+ (for development)

TypeScript Configuration

This package is compatible with all modern TypeScript moduleResolution strategies:

  • "bundler" (recommended for Vite, esbuild, webpack 5+)
  • "node16" / "nodenext" (for Node.js projects)
  • "node" (legacy, but supported)

The package provides dual CommonJS and ES Module builds with proper conditional exports for optimal module resolution and tree-shaking.

Installation

npm install @cratis/components primereact primeicons
# or
yarn add @cratis/components primereact primeicons

primereact and primeicons are peer dependencies — installing them in your app ensures a single copy is shared with the wrappers in this package. The @cratis/arc* packages and react/react-dom are also peer dependencies; you typically already have them.

The following are optional peer dependencies, only required if you use the component that depends on them:

| Component | Optional peer | |---|---| | PivotViewer | pixi.js (canvas) and framer-motion (animated panels) | | DataPage resizable layout | allotment |

Install them only when you reach for the corresponding component.

Usage

Importing Components

You can import components using subpath imports for better tree-shaking:

// Import specific component modules
import { TimeMachine } from '@cratis/components/TimeMachine';
import { DataPage } from '@cratis/components/DataPage';
import { CommandForm } from '@cratis/components/CommandForm';

// Or import from the main entry point
import { TimeMachine, DataPage } from '@cratis/components';

Available Subpath Exports

Components:

  • @cratis/components — package root (re-exports CratisComponentsProvider and the namespaced component groups)
  • @cratis/components/CommandDialog
  • @cratis/components/CommandStepper
  • @cratis/components/CommandForm
  • @cratis/components/CommandForm/fields
  • @cratis/components/Common
  • @cratis/components/DataPage
  • @cratis/components/DataTables
  • @cratis/components/Dialogs
  • @cratis/components/Dropdown
  • @cratis/components/ObjectContentEditor
  • @cratis/components/ObjectNavigationalBar
  • @cratis/components/PivotViewer
  • @cratis/components/SchemaEditor
  • @cratis/components/TimeMachine
  • @cratis/components/Toolbar
  • @cratis/components/types

Stylesheets:

  • @cratis/components/styles — Tailwind utilities + Cratis CSS variable tokens (single stylesheet, recommended)
  • @cratis/components/tokens — only the --cratis-* CSS variable tokens (for consumers using their own utility CSS solution)

Styling

This package ships primarily for its functionality and Arc integrations. Styling is designed to stay out of the way: choose the setup that matches how much control you want, and the other layers stay invisible.

Tip — see each setup live: every Storybook story includes a Styling toolbar (paintbrush icon) that flips between five modes that demonstrate the three setups below: Lara Dark Blue, Lara Light Blue, Themed with custom palette, Unstyled (bare structure), and Unstyled + Tailwind pt. Open any story (yarn dev) and switch modes to see the same component under each setup.

TL;DR — choose a styling setup

| Setup | When | Effort | What you write | |---|---|---|---| | Use a PrimeReact theme | You want components to look good immediately and tweak from there. | Lowest | Theme CSS import + provider | | Use a custom palette on top of a PrimeReact theme | You want PrimeReact's structure but your own colors. | Low | A PrimeReact theme + CSS variable overrides | | Use fully unstyled mode | You're integrating into a tightly controlled design system. | Highest | unstyled: true + a pt preset in CSS or Tailwind |

Why the first two options still load a PrimeReact theme

In PrimeReact 10, every widget's structural CSS (padding, borders, dialog frame, focus rings, button shapes) ships inside the theme file. There is no separate "primitives" stylesheet. So a consumer who doesn't load any PrimeReact theme also has no structural CSS — components render as their raw HTML primitives.

The --cratis-* token layer is therefore an additive Cratis-scoped tint for surfaces our wrappers own (validation error text, the FormElement addon, breadcrumb borders, etc.). It is not, by itself, enough to skin PrimeReact widgets. Override PrimeReact's variables when you want the whole UI in your palette. Use unstyled: true and a pt preset when you want to replace PrimeReact's visuals entirely.

All three setups use the same one-line setup. You can change direction later because the same provider, tokens, and pt hooks stay available.

One-line setup (every styling option)

import '@cratis/components/styles';
import { CratisComponentsProvider } from '@cratis/components';

export const App = () => (
    <CratisComponentsProvider>
        <YourApp />
    </CratisComponentsProvider>
);
  • @cratis/components/styles ships the Tailwind utility classes used inside the package plus the --cratis-* CSS variable token layer that every internal component reads from. (Use @cratis/components/tokens instead if you're bringing your own Tailwind.)
  • CratisComponentsProvider is a thin wrapper over PrimeReact's PrimeReactProvider so Cratis has one place to layer in defaults. Drop in raw PrimeReactProvider if you'd rather.

The three setups below differ only in what else you load on top of this setup.


Use a PrimeReact theme

Load any PrimeReact theme stylesheet alongside Cratis Components. PrimeReact's own widgets paint themselves from the theme, and the --cratis-* tokens cascade to the matching theme variables so Cratis-scoped surfaces follow along.

// 1. Theme first, then Cratis styles so any --cratis-* override wins.
import 'primereact/resources/themes/lara-dark-blue/theme.css';
import 'primeicons/primeicons.css';
import '@cratis/components/styles';

import { CratisComponentsProvider } from '@cratis/components';

export const App = () => (
    <CratisComponentsProvider>
        <YourApp />
    </CratisComponentsProvider>
);

Override a single component with CSS

Plain CSS works fine on top of the theme. Target either PrimeReact's class names or your own className:

/* yourApp.css */
.p-button {
    border-radius: 999px;            /* pill buttons everywhere */
}

.dangerous-button {
    background: var(--cratis-red-500);
    color: white;
}
<Button label="Delete" className="dangerous-button" />

Override a single component with Tailwind

Pass Tailwind utility classes through the wrapper's className prop:

<InputTextField value={c => c.name}
                className="rounded-2xl bg-slate-900 text-slate-50" />

<Dialog title="Confirm" className="shadow-2xl rounded-3xl">
    {/* … */}
</Dialog>

Use this setup when: you're prototyping, building internal tools, or are happy with one of the prebuilt PrimeReact themes.


Use a custom palette on top of a PrimeReact theme

Keep a PrimeReact theme as your structural baseline (so every widget gets its padding, dialog frame, button shape, focus ring, etc.) and override the PrimeReact CSS variables on :root to repaint the whole UI in your own colors. The --cratis-* tokens follow along through tokens.css's cascade, so Cratis-scoped surfaces stay in sync — and you can override the Cratis tokens independently if you want Cratis surfaces to differ from PrimeReact widgets.

With plain CSS

/* palette.override.css — imported once, after @cratis/components/styles */
:root {
    /* PrimeReact variables — these are what PrimeReact widgets read. */
    --surface-0:        #1e293b;
    --surface-100:      #1e293b;
    --surface-ground:   #020617;
    --surface-section:  #0f172a;
    --surface-card:     #1e293b;
    --surface-overlay:  #1e293b;
    --surface-hover:    #334155;
    --surface-border:   #334155;

    --text-color:           #f8fafc;
    --text-color-secondary: #94a3b8;

    --primary-color:      #38bdf8;
    --primary-color-text: #0b1220;

    --highlight-bg:         #1e40af;
    --highlight-text-color: #ffffff;

    --border-radius: 10px;

    /* --cratis-* tokens default to var(--surface-*) etc. via tokens.css, so
       the overrides above flow through automatically. Set these explicitly
       only if you want Cratis-scoped surfaces tinted differently. */
    --cratis-red-500:   #ef4444;
    --cratis-green-500: #22c55e;
}
// 1. PrimeReact theme provides the structure.
import 'primereact/resources/themes/lara-dark-blue/theme.css';
import 'primeicons/primeicons.css';
import '@cratis/components/styles';
// 2. Your palette overrides — must come after the theme so they win.
import './palette.override.css';

Scoped (dark-on-light, light-on-dark, etc.)

PrimeReact variables cascade like any other CSS variable, so an ancestor scope works:

.dark-zone {
    --surface-card: #0b1220;
    --text-color:   #f8fafc;
    --primary-color: #60a5fa;
}
<div className="dark-zone">
    <Dialog title="Always dark">…</Dialog>
</div>

With Tailwind CSS

Tailwind's @layer base is the idiomatic spot — declare the palette once and Tailwind handles cascade and dark mode:

/* app.css */
@import "tailwindcss";
@import "primereact/resources/themes/lara-dark-blue/theme.css";
@import "@cratis/components/styles";

@layer base {
    :root {
        --surface-card:   theme('colors.slate.800');
        --surface-border: theme('colors.slate.700');
        --text-color:     theme('colors.slate.50');
        --primary-color:  theme('colors.sky.400');
        --cratis-red-500: theme('colors.red.500');
    }

    .dark {
        --surface-card: theme('colors.slate.900');
        --text-color:   theme('colors.slate.100');
    }
}

What --cratis-* tokens are for

PrimeReact widgets read PrimeReact's own variables (--surface-card, --text-color, --primary-color, …) directly. Cratis wrappers add some surfaces of their own (inline validation error text, the FormElement addon background, the breadcrumb bottom border, etc.) — those use a parallel set of --cratis-* tokens that default to the PrimeReact value via the cascade defined in tokens.css.

The upshot:

  • Override PrimeReact variables to repaint the whole UI (PrimeReact widgets + Cratis surfaces).
  • Override --cratis-* tokens when you specifically want Cratis surfaces to differ from PrimeReact widgets.

--cratis-* token reference (Cratis-scoped surfaces)

| Group | Tokens | |---|---| | Surfaces | --cratis-surface-0, --cratis-surface-100, --cratis-surface-ground, --cratis-surface-section, --cratis-surface-card, --cratis-surface-overlay, --cratis-surface-hover, --cratis-surface-border | | Text | --cratis-text-color, --cratis-text-color-secondary | | Brand | --cratis-primary-color, --cratis-primary-color-text, --cratis-primary-300, --cratis-primary-400, --cratis-primary-500, --cratis-primary-600 | | Selection | --cratis-highlight-bg, --cratis-highlight-text-color | | Semantic | --cratis-green-500, --cratis-orange-500, --cratis-red-500 | | Geometry | --cratis-border-radius | | Effects | --cratis-focus-ring, --cratis-maskbg |

Each defaults to the PrimeReact variable with the same name minus the --cratis- prefix (e.g. --cratis-surface-cardvar(--surface-card)).

Use this setup when: you want a custom look without writing a PrimeReact theme from scratch, you're shipping multiple palette variants (light/dark/ brand), or you want Cratis-scoped surfaces tinted differently from PrimeReact widgets.


Use fully unstyled mode

Turn off every PrimeReact base style at the provider and supply visuals through PrimeReact's pt (pass-through) mechanism, your own CSS, or both. Components render structurally only and become a blank canvas.

import '@cratis/components/styles';   // tokens + Tailwind utilities still useful for spacing/layout
import { CratisComponentsProvider } from '@cratis/components';

export const App = () => (
    <CratisComponentsProvider value={{ unstyled: true, pt: globalPt }}>
        <YourApp />
    </CratisComponentsProvider>
);

A pt preset in plain CSS

Attach a className from your own stylesheet via a global preset:

// pt-preset.ts
export const globalPt = {
    button: {
        root: { className: 'my-btn' },
    },
    dialog: {
        root: { className: 'my-dialog' },
        header: { className: 'my-dialog__header' },
        content: { className: 'my-dialog__body' },
    },
    inputtext: {
        root: { className: 'my-input' },
    },
} as const;
/* yourApp.css */
.my-btn {
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 1rem;
    background: var(--cratis-primary-color);
    color: var(--cratis-primary-color-text);
    border: none;
    border-radius: var(--cratis-border-radius);
    cursor: pointer;
}

.my-dialog__header {
    padding: 1rem 1.25rem;
    background: var(--cratis-surface-card);
    border-bottom: 1px solid var(--cratis-surface-border);
    font-weight: 600;
}

A pt preset in Tailwind

Same shape, Tailwind utilities as the class strings:

// pt-preset.ts
export const globalPt = {
    button: {
        root: { className: 'inline-flex items-center px-4 py-2 rounded-lg bg-sky-500 text-white hover:bg-sky-400 disabled:opacity-50' },
    },
    dialog: {
        root:    { className: 'rounded-2xl shadow-2xl overflow-hidden' },
        header:  { className: 'px-5 py-3 bg-slate-800 text-slate-50 font-semibold border-b border-slate-700' },
        content: { className: 'p-5 bg-slate-900 text-slate-100' },
    },
    inputtext: {
        root: { className: 'w-full px-3 py-2 rounded-md bg-slate-800 text-slate-50 border border-slate-700 focus:border-sky-400 focus:outline-none' },
    },
} as const;

Per-instance overrides

Anything global can be overridden per-instance — useful when one component needs to look different:

<Dialog
    title="Brand callout"
    pt={{ root: { className: 'rounded-none' },
          header: { className: 'bg-pink-600 text-white' } }}>
    …
</Dialog>

<InputTextField value={c => c.name}
                pt={{ root: { className: 'border-2 border-pink-500' } }} />

Composite components in unstyled mode

DataPage and StepperCommandDialog compose multiple PrimeReact widgets and expose explicit per-slot props. The global pt reaches every internal widget; per-instance overrides target the inner slot directly:

<DataPage<AllAuthors, Author, never>
    title="Authors" query={AllAuthors}
    tablePt={{ table: { className: 'min-w-full divide-y divide-slate-700' } }}
    menubarPt={{ root: { className: 'px-3 py-2 bg-slate-900' } }}>
    <DataPage.MenuItems>…</DataPage.MenuItems>
    <DataPage.Columns>…</DataPage.Columns>
</DataPage>

<StepperCommandDialog<RegisterOrder> command={RegisterOrder} title="New order"
    /* pt targets the Stepper */
    pt={{ stepperpanel: { content: { className: 'pt-6' } } }}
    /* dialogPt targets the outer Dialog */
    dialogPt={{ header: { className: 'bg-slate-900' } }}>
    …
</StepperCommandDialog>

ObjectContentEditor, ObjectNavigationalBar, and SchemaEditor accept only className on the root — restyle their internals via the global pt preset.

Use this setup when: you have a design system to honor, you're matching a brand kit, or you want zero PrimeReact CSS in the final bundle.


Combining styling setups

The styling options compose, so you don't have to choose one for the whole app:

  • Themed with one unstyled component — keep the PrimeReact theme and pass unstyled per-component to opt that one widget out:
    <Dialog title="Custom" unstyled pt={brandDialogPt}>…</Dialog>
  • Unstyled with one themed island — wrap a subtree in a second CratisComponentsProvider that restores defaults:
    <CratisComponentsProvider value={{ unstyled: true, pt: globalPt }}>
        <App />
        <CratisComponentsProvider value={{ unstyled: false }}>
            <PrimeReactThemedSubtree />
        </CratisComponentsProvider>
    </CratisComponentsProvider>
  • Dark mode — scope the palette overrides to .dark (override --surface-card, --text-color, --primary-color, etc., plus any --cratis-* tokens you want to diverge) and toggle the class on the root element. PrimeReact widgets and Cratis surfaces both follow the cascade.

Per-component pt cheat sheet

Three patterns, depending on how much PrimeReact a wrapper composes:

  1. Single-widget wrappersDialog, every CommandForm field, EventsView, and Dropdown forward pt, ptOptions, unstyled, and className straight to their inner PrimeReact component.
  2. Multi-slot compositesStepperCommandDialog (pt for Stepper, dialogPt for Dialog), DataPage (tablePt for DataTable, menubarPt for Menubar), and DataTableForQuery / DataTableForObservableQuery (pt for DataTable, paginatorPt for Paginator) — each slot has *PtOptions, *Unstyled, and (where applicable) *ClassName siblings.
  3. Large compositesObjectContentEditor, ObjectNavigationalBar, SchemaEditor expose className only; restyle internals via the global pt preset.

What is not fully pass-through

A small number of internal usages opt into PrimeReact's slot-rendering by name (for example, a custom Menubar item template uses p-menuitem-link / p-menuitem-text to match the surrounding default-rendered items). These are correct contracts with PrimeReact's own slot rendering, not hard-coded theming — they have no effect in unstyled mode and match the rest of the menu in themed mode.

BusyIndicatorDialog only honors the global pt set via CratisComponentsProvider; it does not accept per-instance pt because its request type is owned by @cratis/arc.react.

Troubleshooting

Module Resolution Errors

If you encounter errors like:

Cannot find module '@cratis/components/TimeMachine' or its corresponding type declarations.

Solution: Ensure you're using the correct case-sensitive import paths (e.g., TimeMachine, not timeMachine).

If using TypeScript 4.7+, try updating your tsconfig.json:

{
  "compilerOptions": {
    "moduleResolution": "bundler"  // or "node16" / "nodenext"
  }
}

Import Errors

Ensure you're using the correct import paths. The package uses case-sensitive paths that match the actual component names.