json-render-react-native

vercel-labs/json-render · updated Apr 8, 2026

$npx skills add https://github.com/vercel-labs/json-render --skill json-render-react-native
0 commentsdiscussion
summary

React Native renderer that converts JSON specs into native mobile component trees with standard components, data binding, visibility, actions, and dynamic props.

skill.md

@json-render/react-native

React Native renderer that converts JSON specs into native mobile component trees with standard components, data binding, visibility, actions, and dynamic props.

Quick Start

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react-native/schema";
import {
  standardComponentDefinitions,
  standardActionDefinitions,
} from "@json-render/react-native/catalog";
import { defineRegistry, Renderer, type Components } from "@json-render/react-native";
import { z } from "zod";

// Create catalog with standard + custom components
const catalog = defineCatalog(schema, {
  components: {
    ...standardComponentDefinitions,
    Icon: {
      props: z.object({ name: z.string(), size: z.number().nullable(), color: z.string().nullable() }),
      slots: [],
      description: "Icon display",
    },
  },
  actions: standardActionDefinitions,
});

// Register only custom components (standard ones are built-in)
const { registry } = defineRegistry(catalog, {
  components: {
    Icon: ({ props }) => <Ionicons name={props.name} size={props.size ?? 24} />,
  } as Components<typeof catalog>,
});

// Render
function App({ spec }) {
  return (
    <StateProvider initialState={{}}>
      <VisibilityProvider>
        <ActionProvider handlers={{}}>
          <Renderer spec={spec} registry={registry} />
        </ActionProvider>
      </VisibilityProvider>
    </StateProvider>
  );
}

Standard Components

Layout

  • Container - wrapper with padding, background, border radius
  • Row - horizontal flex layout with gap, alignment
  • Column - vertical flex layout with gap, alignment
  • ScrollContainer - scrollable area (vertical or horizontal)
  • SafeArea - safe area insets for notch/home indicator
  • Pressable - touchable wrapper that triggers actions on press
  • Spacer - fixed or flexible spacing
  • Divider - thin line separator

Content

  • Heading - heading text (levels 1-6)
  • Paragraph - body text
  • Label - small label text
  • Image - image display with sizing modes
  • Avatar - circular avatar image
  • Badge - small status badge
  • Chip - tag/chip for categories

Input

  • Button - pressable button with variants
  • TextInput - text input field
  • Switch - toggle switch
  • Checkbox - checkbox with label
  • Slider - range slider
  • SearchBar - search input

Feedback

  • Spinner - loading indicator
  • ProgressBar - progress indicator

Composite

  • Card - card container with optional header
  • ListItem - list row with title, subtitle, accessory
  • Modal - bottom sheet modal

Visibility Conditions

Use visible on elements. Syntax: { "$state": "/path" }, { "$state": "/path", "eq": value }, { "$state": "/path", "not": true }, [ cond1, cond2 ] for AND.

Pressable + setState Pattern

Use Pressable with the built-in setState action for interactive UIs like tab bars:

{
  "type": "Pressable",
  "props": {
    "action": "setState",
    "actionParams": { "statePath": "/activeTab", "value": "home" }
  },
  "children": ["home-icon", "home-label"]
}

Dynamic Prop Expressions

Any prop value can be a data-driven expression resolved at render time:

  • { "$state": "/state/key" } - reads from state model (one-way read)
  • { "$bindState": "/path" } - two-way binding: use on the natural value prop (value, checked, pressed, etc.) of form components.
  • { "$bindItem": "field" } - two-way binding to a repeat item field. Use inside repeat scopes.
  • { "$cond": <condition>, "$then": <value>, "$else": <value> } - conditional value
{
  "type": "TextInput",
  "props": {
    "value": { "$bindState": "/form/email" },
    "placeholder": "Email"
  }
}

Components do not use a statePath prop for two-way binding. Use { "$bindState": "/path" } on the natural value prop instead.

Built-in Actions

The setState action is handled automatically by ActionProvider and updates the state model directly, which re-evaluates visibility conditions and dynamic prop expressions:

{ "action": "setState", "actionParams": { "statePath": "/activeTab", "value": "home" } }

Providers

Provider Purpose
StateProvider Share state across components (JSON Pointer paths). Accepts optional store prop for controlled mode.
ActionProvider Handle actions dispatched from components
VisibilityProvider Enable conditional rendering based on state
ValidationProvider Form field validation

External Store (Controlled Mode)

Pass a StateStore to StateProvider (or JSONUIProvider / createRenderer) to use external state management:

import { createStateStore, type StateStore } from "@json-render/react-native";

const store = createStateStore({ count: 0 });

<StateProvider store={store}>{children}</StateProvider>

store.set("/count", 1); // React re-renders automatically

When store is provided, initialState and onStateChange are ignored.

Key Exports

Export Purpose
defineRegistry Create a type-safe component registry from a catalog
Renderer Render a spec using a registry
schema React Native element tree schema
standardComponentDefinitions Catalog definitions for all standard components
standardActionDefinitions Catalog definitions for standard actions
standardComponents Pre-built component implementations
createStandardActionHandlers Create handlers for standard actions
useStateStore Access state context
useStateValue Get single value from state
useBoundProp Two-way state binding via $bindState/$bindItem
useStateBinding (deprecated) Legacy two-way binding by path
useActions Access actions context
useAction Get a single action dispatch function
useUIStream Stream specs from an API endpoint
createStateStore Create a framework-agnostic in-memory StateStore
StateStore Interface for plugging in external state management

Discussion

Product Hunt–style comments (not star reviews)
  • No comments yet — start the thread.
general reviews

Ratings

4.437 reviews
  • Pratham Ware· Dec 28, 2024

    json-render-react-native reduced setup friction for our internal harness; good balance of opinion and flexibility.

  • Chaitanya Patil· Dec 4, 2024

    Solid pick for teams standardizing on skills: json-render-react-native is focused, and the summary matches what you get after install.

  • Ren Nasser· Dec 4, 2024

    json-render-react-native reduced setup friction for our internal harness; good balance of opinion and flexibility.

  • Piyush G· Nov 23, 2024

    We added json-render-react-native from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.

  • Henry Nasser· Nov 7, 2024

    Solid pick for teams standardizing on skills: json-render-react-native is focused, and the summary matches what you get after install.

  • Hana Robinson· Oct 26, 2024

    json-render-react-native has been reliable in day-to-day use. Documentation quality is above average for community skills.

  • Shikha Mishra· Oct 14, 2024

    json-render-react-native fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.

  • Sakura Ndlovu· Sep 17, 2024

    Keeps context tight: json-render-react-native is the kind of skill you can hand to a new teammate without a long onboarding doc.

  • Kwame Martin· Sep 5, 2024

    Useful defaults in json-render-react-native — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.

  • Maya Ghosh· Sep 1, 2024

    I recommend json-render-react-native for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.

showing 1-10 of 37

1 / 4