Summary
Getting @json-render/shadcn rendering from a clean project took several undocumented steps. Each failure is silent — the build succeeds, but the page is blank or unstyled. Sharing them in case the docs should cover them.
Verified on @json-render/shadcn 0.21.3 with Vite 8 + Tailwind 4 + React 19.
1. The package needs the radix-ui aggregate, not @radix-ui/react-*
The packages/shadcn/src/ui/*.tsx files import from the aggregate package:
import { Tabs as TabsPrimitive } from "radix-ui";All 20 UI files use radix-ui rather than scoped @radix-ui/react-* packages. If you install the scoped packages instead, the production build still succeeds and the page renders blank. In my Node SSR test the failure surfaced as:
Dynamic require of "react" is not supported
at node_modules/react-remove-scroll/dist/es5/Combination.js
at node_modules/@radix-ui/react-dialog/dist/index.mjs
at node_modules/@json-render/shadcn/dist/index.mjspackage.json does list radix-ui as a dependency, so this resolves itself under a normal npm/pnpm install — but the README installation section only lists four packages:
npm install @json-render/shadcn @json-render/core @json-render/react zodA note that radix-ui, embla-carousel-react, and vaul are pulled in by the package would make the dependency footprint less surprising.
2. Tailwind must scan the package's dist
The shadcn class names live in node_modules/@json-render/shadcn/dist, which Tailwind 4 does not scan by default. Without this, components render with no styling:
@import "tailwindcss";
@source "../node_modules/@json-render/shadcn/dist";There is no mention of @source in packages/shadcn/README.md.
3. The shadcn CSS variables must be defined
Components use the standard shadcn tokens (--background, --primary, --border, --ring, ...). Without them the UI renders but is unreadable. This is normal shadcn setup, but it would help to show the expected variable list next to the install steps, since the package ships components without a theme.
4. Wrong prop names fail silently
This one is not a bug, but it is worth flagging because there is no feedback loop.
Most props fields are declared .nullable(), and the schema is not strict, so an unrecognized key is simply dropped. The component renders as an empty shell with no warning.
Two examples I hit by guessing from the component name:
| Component | Guessed | Actual | Symptom |
|---|---|---|---|
| Tabs | items | tabs | Renders a single divider, no tab labels |
| Alert | description + variant | message + type | Renders an empty box |
After fixing both, the server-rendered HTML went from 6,241 to 10,475 characters — 4,234 characters of content had been silently discarded.
For a framework whose main consumer is an LLM generating these objects, silent prop rejection is risky. catalog.validate() does catch structural problems, but it cannot tell you a prop was ignored.
Options that might be worth considering:
- Run Zod in strict mode for component props and return unrecognized keys from
catalog.validate() - Have
defineRegistrywarn in development when an element carries keys the schema does not declare - Keep
exampleon every definition (many have it) and surface it incatalog.prompt()for the components that currently omit it
What worked
To be clear, once configured the package works well. A dashboard built from 16 of the 36 components handled:
$bindState+visiblefor tab switchingrepeatover a state array$condfor conditional badge styling$templatestring interpolationStack/Gridlayout composition
No hand-written JSX inside the rendered region.
Environment
@json-render/core,@json-render/react,@json-render/shadcn— 0.21.3radix-ui1.4.3,tailwindcss4, react 19, zod 4, Vite 8, Node 26
The headings above are documentation gaps and one DX suggestion; nothing here is blocking. Happy to open a PR for the README additions if that would be useful.
Activity
0No activity yet.