Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

directives — json-render skill: formatting and i18n directives

Pre-built directives for json-render: formatting, math, string handling, i18n. Wire them into your catalog and renderer with one import.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add vercel-labs/json-render --skill directives -a claude-code
Open on GitHub

What directives does

This skill ships a set of custom directives for @json-render/core. You get $format, $math, $concat, $count, $truncate, $pluralize, $join, plus the createI18nDirective factory for $t. They live in standardDirectives, ready to plug into prompt generation and any renderer.

Directives compose. Each resolver calls resolvePropValue on its inputs, so $format can wrap $math, and $math can read from $state. Resolution flows inside-out: state first, then computation, then formatting. The i18n factory takes a config with locales, messages, and an optional fallback locale.

For custom directives, use defineDirective from @json-render/core. The name must start with $ and avoid built-in keys like $state, $cond, or $template. Call resolvePropValue on sub-values inside your resolver or composition breaks — worth keeping in mind when you extend the set.

What it helps with

  • format dates, currency, numbers and percentages via Intl
  • add, subtract, round and divide values inside a spec
  • concatenate strings from state fields
  • truncate long text with a custom suffix
  • handle singular and plural word forms

Example prompts for the agent

  • Wire standardDirectives from @json-render/directives into the catalog and renderer
  • Define a custom directive with defineDirective, name starting with $
  • Spread createI18nDirective into the directives array

How to install directives

1Skills CLI (Vercel)

npx skills add vercel-labs/json-render --skill directives -a claude-code

2Manually: put the files in place

~/.claude/skills/directives/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/directives/

From the same set5

The whole set →

Similar

chakra-ui-migrate chakra-ui A migration skill that guides projects from Chakra UI v2 to v3. It handles package cleanups, codemods, provider setup, and updated component props. Claude Code CX Codex Cursor +1 1,800installs react-native-architecture Seth Hobson A skill for Claude Code, Codex and Cursor that hands your agent project layout, navigation, native modules and offline sync patterns for React Native on Expo. Claude Code CX Codex Cursor 15,087installs winui3-migration-guide official github This skill helps move UWP code to WinUI 3 and Windows App SDK. Use it to check API replacements, namespaces, and common Copilot mistakes. GitHub Copilot 5,700installs accessibility-compliance Seth Hobson This skill guides accessibility audits and interface work involving keyboard navigation, screen readers, and forms. Use it when building against WCAG 2.2. Claude Code CX Codex Cursor 14,596installs site-md official google-labs-code Generates a .stitch/SITE.md constitution file from requirements or project briefs for the Stitch Build Loop. Claude Code CX Codex Cursor +1 3,600installs ima-sdk-client-side official Google LLC This skill supports Google IMA SDK integrations for client-side video and audio ads requested through VAST or VMAP. Use it for websites, apps, and TV platforms. Claude Code Gemini CLI CX Codex 4,500installs frontend-design official anthropics This skill guides intentional visual design for new interfaces and redesigns. Use it when a generic generated UI is not enough. Claude Code Claude.ai 1,025,790installs design-taste-frontend Leonxlnx This skill directs the design of public pages and work screens, then checks the result in a browser through screenshots. Use it when an interface feels generic or unfinished. Claude Code CX Codex Cursor +1 673,100installs

Questions about directives

How do I install directives in Claude Code?

Run npx skills add vercel-labs/json-render --skill directives -a claude-code. The skill lands in ~/.claude/skills/directives/SKILL.md.

What does the directives skill do?

It provides ready-made directives for json-render: $format, $math, $concat, $count, $truncate, $pluralize, $join, and the createI18nDirective factory. Import standardDirectives to wire them into your catalog and renderer.

How do I create a custom directive?

Import defineDirective from @json-render/core. The name must start with $ and must not conflict with built-in keys: $state, $cond, $computed, $template, $item, $index, $bindState, $bindItem. Call resolvePropValue on sub-values to keep composition working.

Source text

SKILL.md · Apache-2.0
---
name: directives
description: Pre-built custom directives for json-render — formatting, math, string manipulation, and i18n. Use when working with @json-render/directives, defining custom directives with defineDirective, or adding $format, $math, $concat, $count, $truncate, $pluralize, $join, or $t to specs.
---

# @json-render/directives

Pre-built custom directives for `@json-render/core`. Drop them into your catalog and renderer to add formatting, math, string manipulation, and i18n.

## Quick Start

```typescript
import { standardDirectives } from '@json-render/directives';

// Wire into prompt generation
const prompt = catalog.prompt({ directives: standardDirectives });

// Wire into the renderer (React example)
import { JSONUIProvider, Renderer } from '@json-render/react';

<JSONUIProvider registry={registry} directives={standardDirectives}>
  <Renderer spec={spec} registry={registry} />
</JSONUIProvider>
```

To add factory directives like `createI18nDirective`, spread the array:

```typescript
import { standardDirectives, createI18nDirective } from '@json-render/directives';

const directives = [...standardDirectives, createI18nDirective(config)];
```

## Defining Custom Directives

Use `defineDirective` from `@json-render/core`:

```typescript
import { defineDirective, resolvePropValue } from '@json-render/core';
import { z } from 'zod';

const doubleDirective = defineDirective({
  name: '$double',
  description: 'Double a numeric value.',
  schema: z.object({
    $double: z.unknown(),
  }),
  resolve(value, ctx) {
    const resolved = resolvePropValue(value.$double, ctx);
    return (resolved as number) * 2;
  },
});
```

Rules:
- Name must start with `$`
- Name must not conflict with built-in keys (`$state`, `$cond`, `$computed`, `$template`, `$item`, `$index`, `$bindState`, `$bindItem`)
- Resolvers should call `resolvePropValue` on sub-values to support composition

## Built-in Directives

### `$format` — Locale-aware value formatting

Formats values using `Intl` formatters. Supports `date`, `currency`, `number`, and `percent`.

```json
{ "$format": "currency", "value": { "$state": "/cart/total" }, "currency": "USD" }
{ "$format": "date", "value": { "$state": "/user/createdAt" } }
{ "$format": "number", "value": 1234567, "notation": "compact" }
{ "$format": "percent", "value": 0.75 }
{ "$format": "date", "value": { "$state": "/post/createdAt" }, "style": "relative" }
```

Fields: `$format` (date | currency | number | percent), `value` (any expression), `locale?` (string), `currency?` (string, default "USD"), `notation?` (string), `style?` ("relative" for relative dates), `options?` (extra Intl options).

### `$math` — Arithmetic operations

```json
{ "$math": "add", "a": { "$state": "/subtotal" }, "b": { "$state": "/tax" } }
{ "$math": "round", "a": 3.7 }
```

Operations: `add`, `subtract`, `multiply`, `divide`, `mod`, `min`, `max`, `round`, `floor`, `ceil`, `abs`. Unary ops (`round`, `floor`, `ceil`, `abs`) only use `a`. Division by zero returns `0`.

Fields: `$math` (operation enum), `a?` (first operand, default 0), `b?` (second operand, default 0).

### `$concat` — String concatenation

```json
{ "$concat": [{ "$state": "/user/firstName" }, " ", { "$state": "/user/lastName" }] }
```

Fields: `$concat` (array of values to resolve and join into a string).

### `$count` — Array/string length

```json
{ "$count": { "$state": "/cart/items" } }
```

Returns `.length` of arrays or strings, `0` for other types.

Fields: `$count` (value to count).

### `$truncate` — Text truncation

```json
{ "$truncate": { "$state": "/post/body" }, "length": 140, "suffix": "..." }
```

Fields: `$truncate` (value to truncate), `length?` (max chars, default 100), `suffix?` (string, default "...").

### `$pluralize` — Singular/plural forms

```json
{ "$pluralize": { "$state": "/cart/itemCount" }, "one": "item", "other": "items", "zero": "no items" }
```

Output: `"3 items"`, `"1 item"`, or `"no items"`.

Fields: `$pluralize` (count value), `one` (singular label), `other` (plural label), `zero?` (zero label).

### `$join` — Join array elements

```json
{ "$join": { "$state": "/tags" }, "separator": ", " }
```

Fields: `$join` (array to join), `separator?` (string, default ", ").

### `createI18nDirective` — Internationalization factory

```typescript
import { createI18nDirective } from '@json-render/directives';

const tDirective = createI18nDirective({
  locale: 'en',
  messages: {
    en: { "greeting": "Hello, {{name}}!", "checkout.submit": "Place Order" },
    es: { "greeting": "Hola, {{name}}!", "checkout.submit": "Realizar Pedido" },
  },
  fallbackLocale: 'en',
});
```

Usage in specs:

```json
{ "$t": "checkout.submit" }
{ "$t": "greeting", "params": { "name": { "$state": "/user/name" } } }
```

Fields: `$t` (translation key), `params?` (interpolation parameters, values accept expressions).

Config: `locale` (current locale), `messages` (Record<locale, Record<key, string>>), `fallbackLocale?` (fallback when key missing).

## Composition

Directives compose naturally — each resolver calls `resolvePropValue` on its inputs, so directives can wrap other directives or built-in expressions:

```json
{
  "$format": "currency",
  "value": { "$math": "multiply", "a": { "$state": "/price" }, "b": { "$state": "/qty" } },
  "currency": "USD"
}
```

Resolves inside-out: `$state` reads from state, `$math` multiplies, `$format` formats as currency.

## Wiring into Renderers

All four renderers (React, Vue, Svelte, Solid) accept `directives` on their provider and `createRenderer` output:

```tsx
// Provider pattern
<JSONUIProvider registry={registry} directives={directives}>
  <Renderer spec={spec} registry={registry} />
</JSONUIProvider>

// createRenderer pattern
const MyRenderer = createRenderer(catalog, components);
<MyRenderer spec={spec} directives={directives} />
```

For prompt generation, pass the same array:

```typescript
const prompt = catalog.prompt({ directives });
```

## Key Exports

| Export | Purpose |
|--------|---------|
| `formatDirective` | `$format` directive definition |
| `mathDirective` | `$math` directive definition |
| `concatDirective` | `$concat` directive definition |
| `countDirective` | `$count` directive definition |
| `truncateDirective` | `$truncate` directive definition |
| `pluralizeDirective` | `$pluralize` directive definition |
| `joinDirective` | `$join` directive definition |
| `createI18nDirective` | Factory for `$t` i18n directive |
| `standardDirectives` | Array of all 7 non-factory directives |
| `I18nConfig` | Type for i18n configuration |

© vercel-labs · Apache-2.0 · vercel-labs/json-render

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor