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

jsonforms-shadcn-renderers

v0.2.0

Published

shadcn/ui-styled renderer set for JSONForms, with full control/layout coverage and overridable components

Downloads

92

Readme

jsonforms-shadcn-renderers

A JSONForms renderer set styled with shadcn/ui. It's self-contained — built directly on Radix primitives (the default) or on Base UI (via the /base-ui entry) and Tailwind, the same way npx shadcn add would generate a component — so it needs no dependency on your project's local components/ui files, and every component is individually overridable if you want to use your own anyway.

Installation

npm install jsonforms-shadcn-renderers @jsonforms/core @jsonforms/react

Tailwind setup (required)

This package ships no CSS of its own — every class it uses is a static Tailwind utility baked into its compiled JS, styled entirely through your project's existing shadcn theme tokens (--primary, --background, --radius, ...). Tailwind v4 excludes node_modules from its automatic source scan, so you need one extra line in your global stylesheet telling it to look inside this package:

@import 'tailwindcss';

@source '../node_modules/jsonforms-shadcn-renderers';

(adjust the relative path to wherever your CSS file actually sits relative to node_modules).

Add the package to your content glob in tailwind.config.js, and make sure tailwindcss-animate (or tw-animate-css) is installed for the animation utilities some components (Accordion, Select, Popover) use:

module.exports = {
  content: ['./src/**/*.{ts,tsx}', './node_modules/jsonforms-shadcn-renderers/dist/**/*.{js,cjs}'],
  plugins: [require('tailwindcss-animate')],
};

Basic usage

No provider, no config — pass the renderer and cell arrays straight into <JsonForms>:

import { JsonForms } from '@jsonforms/react';
import { shadcnRenderers, shadcnCells } from 'jsonforms-shadcn-renderers';

function MyForm() {
  return (
    <JsonForms
      schema={schema}
      uischema={uischema}
      data={data}
      renderers={shadcnRenderers}
      cells={shadcnCells}
      onChange={({ data, errors }) => console.log(data, errors)}
    />
  );
}

Using Base UI

The same renderers are also available built on Base UI (@base-ui/react) instead of Radix. The public API is identical (shadcnRenderers, shadcnCells, createShadcnRenderers, createShadcnCells, JsonFormsShadcnProvider, useUIComponents, withComponentsOverride, and the types) — only the import path changes:

import { shadcnRenderers, shadcnCells } from 'jsonforms-shadcn-renderers/base-ui';

The built-ins are shadcn's base-nova components. To override them, use the output of npx shadcn add from a base-nova project as drop-ins, exactly like the Radix flavor:

import { JsonFormsShadcnProvider } from 'jsonforms-shadcn-renderers/base-ui';
import { Input } from '@/components/ui/input';
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';

<JsonFormsShadcnProvider
  components={{
    Input,
    select: {
      Root: Select,
      Trigger: SelectTrigger,
      Value: SelectValue,
      Content: SelectContent,
      Item: SelectItem,
      Group: SelectGroup,
      Label: SelectLabel,
      Separator: SelectSeparator,
    },
  }}
>
  <MyForm />
</JsonFormsShadcnProvider>;

Two differences from the Radix flavor:

  • The multi-select options: { format: 'combobox' } renders with Base UI Combobox + chips instead of cmdk. To override it, replace the combobox family (not command, which doesn't exist here).
  • There is no popover.Anchor; the combobox family's useAnchor handles anchoring.

The Base UI compound families are select, radioGroup, popover, calendar, combobox, table, tabs, accordion, and card; the simple slots are the same as in the Radix flavor.

No Radix at runtime. The /base-ui entry never imports Radix or cmdk, so bundlers don't include them (they are still installed as dependencies of the package for the root entry). This is enforced by npm run check:no-radix (part of check:package, so it runs before every publish), by ESLint import restrictions, and by a module-graph test.

The Tailwind setup is the same — the one @source line covers both entries.

Don't import both entries in one app: each has its own context, so a provider from one won't reach renderers from the other.

Supported controls, layouts, and combinators

| Schema / uischema shape | Renders as | | ------------------------------------------------------------------------------------ | -------------------------------------------------- | | type: 'string' | Text input | | type: 'string', options: { multi: true } | Textarea | | format: 'date' | Date picker (Popover + Calendar) | | format: 'time' | Time input | | format: 'date-time' | Date + time picker | | type: 'number' / 'integer' | Number input | | minimum + maximum + default, options: { slider: true } | Slider | | type: 'boolean' | Checkbox | | type: 'boolean', options: { toggle: true } | Switch | | enum: [...] | Select | | enum: [...], options: { format: 'radio' } | Radio group | | oneOf: [{ const, title }, ...] | Select | | oneOf: [{ const, title }, ...], options: { format: 'radio' } | Radio group | | type: 'array', items.enum: [...] | Checkbox list | | type: 'array', items.enum: [...], options: { format: 'combobox' } | Searchable multi-select combobox | | type: 'array', items: { type: 'string' \| 'number' \| ... } | Add/remove list | | type: 'array', items: { type: 'object' } | Table (add/remove rows) | | type: 'array', items: { type: 'object' }, options: { layout: 'master-detail' } | Accordion, one item per entry | | type: 'object' | Recursively rendered child layout | | oneOf (object-level) | One-branch selector + the selected branch's fields | | anyOf (object-level) | Same single-branch UX as oneOf (see note below) | | allOf (object-level) | Every branch's fields rendered together | | VerticalLayout / HorizontalLayout | Flex column / row | | Group | Card with a title | | Label | Heading | | Categorization | Tabs | | a rule (SHOW/HIDE/ENABLE/DISABLE) on any element | Respected automatically |

Validation is computed by JSONForms core itself (Ajv) — this package only displays the resulting error messages, required-field markers, and description help text; there's no validation logic of its own to configure.

A note on anyOf: JSON Schema's anyOf technically allows data to satisfy more than one branch at once, but a form UI editing multiple overlapping branches simultaneously isn't practically meaningful, so — matching how JSONForms' own official renderer sets handle it — anyOf is treated the same as oneOf: pick one branch, edit it.

Cells vs. controls

Every control above also has a compact "cell" counterpart (shadcnCells) — the same field without its label/description/error chrome, automatically used for the columns inside an array-of-objects table instead of the full control.

Overriding components

By default every field is one of this package's own built-in components. You can override any subset — either app-wide with a provider, or scoped to a single <JsonForms> instance without one.

Simple slots (Input, Textarea, Label, Checkbox, Switch, Slider, Button, Badge, Separator) can be overridden individually. Compound families (select, radioGroup, popover, calendar, command, table, tabs, accordion, card) must be replaced as a whole — Radix/cmdk/Base UI compound pieces share internal context, so mixing a custom select.Trigger with the built-in select.Content breaks at runtime. (In the Base UI flavor command is replaced by combobox; see Using Base UI.)

Because every built-in is generated the same way npx shadcn add would generate it for your own project, your own literal @/components/ui/input.tsx (or a whole custom select family) is a drop-in replacement with zero adapter code.

App-wide, via provider

import { JsonFormsShadcnProvider } from 'jsonforms-shadcn-renderers';
import { Input } from '@/components/ui/input';

function App() {
  return (
    <JsonFormsShadcnProvider components={{ Input }}>
      <MyForm />
    </JsonFormsShadcnProvider>
  );
}

Scoped, without a provider

import { createShadcnRenderers, createShadcnCells } from 'jsonforms-shadcn-renderers';
import { Input } from '@/components/ui/input';

const renderers = createShadcnRenderers({ Input });
const cells = createShadcnCells({ Input });

<JsonForms renderers={renderers} cells={cells} /* ... */ />;

Live example

The apps/playground app in this repo is a real Vite + shadcn/ui project with this package installed as a plain dependency — a page per control family, a kitchen-sink page exercising everything at once, and an overrides page. Run it locally with npm run dev from the repo root. apps/playground-base-ui is the same thing for the Base UI flavor (jsonforms-shadcn-renderers/base-ui); run it with npm run dev:base-ui.

Local development

From the repo root:

npm run dev:lib      # build the renderer package in watch mode
npm run test          # run its test suite
npm run typecheck      # typecheck every workspace
npm run lint             # lint every workspace

How the vendored Base UI components are regenerated is described in shadcn-base-ui/README.md.

License

MIT. Components in src/components/ui and src/components/base-ui are derived from shadcn/ui (MIT, © shadcn); see LICENSE.