mcpbeat

Vue

vercel-labs/vue

Vue 3 renderer for json-render. Use when building Vue UIs from JSON specs, working with @json-render/vue, defining Vue component registries, or rendering AI-generated specs in Vue.

1k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
15821
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/vercel-labs/json-render --skill vue

The instruction itself

16 sections, as written by the author

@json-render/vue

Vue 3 renderer that converts JSON specs into Vue component trees with data binding, visibility, and actions.

Installation

npm install @json-render/vue @json-render/core zod

Peer dependencies: vue ^3.5.0 and zod ^4.0.0.

Quick Start

Create a Catalog

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/vue/schema";
import { z } from "zod";

export const catalog = defineCatalog(schema, {
  components: {
    Card: {
      props: z.object({ title: z.string(), description: z.string().nullable() }),
      description: "A card container",
    },
    Button: {
      props: z.object({ label: z.string(), action: z.string() }),
      description: "A clickable button",
    },
  },
  actions: {},
});

Define Registry with h() Render Functions

import { h } from "vue";
import { defineRegistry } from "@json-render/vue";
import { catalog } from "./catalog";

export const { registry } = defineRegistry(catalog, {
  components: {
    Card: ({ props, children }) =>
      h("div", { class: "card" }, [
        h("h3", null, props.title),
        props.description ? h("p", null, props.description) : null,
        children,
      ]),
    Button: ({ props, emit }) =>
      h("button", { onClick: () => emit("press") }, props.label),
  },
});

Render Specs

<script setup lang="ts">
import { StateProvider, ActionProvider, Renderer } from "@json-render/vue";
import { registry } from "./registry";

const spec = { root: "card-1", elements: { /* ... */ } };
</script>

<template>
  <StateProvider :initial-state="{ form: { name: '' } }">
    <ActionProvider :handlers="{ submit: handleSubmit }">
      <Renderer :spec="spec" :registry="registry" />
    </ActionProvider>
  </StateProvider>
</template>

Providers

| Provider | Purpose |

|----------|---------|

| StateProvider | Share state across components (JSON Pointer paths). Accepts initialState or store for controlled mode. |

| ActionProvider | Handle actions dispatched via the event system |

| VisibilityProvider | Enable conditional rendering based on state |

| ValidationProvider | Form field validation |

Composables

| Composable | Purpose |

|------------|---------|

| useStateStore() | Access state context (state as ShallowRef, get, set, update) |

| useStateValue(path) | Get single value from state |

| useIsVisible(condition) | Check if a visibility condition is met |

| useActions() | Access action context |

| useAction(binding) | Get a single action dispatch function |

| useFieldValidation(path, config) | Field validation state |

| useBoundProp(propValue, bindingPath) | Two-way binding for $bindState/$bindItem |

Note: useStateStore().state returns a ShallowRef<StateModel> — use state.value to access.

External Store (StateStore)

Pass a StateStore to StateProvider to wire json-render to Pinia, VueUse, or any state management:

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

const store = createStateStore({ count: 0 });
<StateProvider :store="store">
  <Renderer :spec="spec" :registry="registry" />
</StateProvider>

Dynamic Prop Expressions

Props support $state, $bindState, $cond, $template, $computed. Use { "$bindState": "/path" } on the natural value prop for two-way binding.

Visibility Conditions

{ "$state": "/user/isAdmin" }
{ "$state": "/status", "eq": "active" }
{ "$state": "/maintenance", "not": true }
[ cond1, cond2 ]  // implicit AND

Built-in Actions

setState, pushState, removeState, and validateForm are built into the Vue schema and handled by ActionProvider:

{
  "action": "setState",
  "params": { "statePath": "/activeTab", "value": "settings" }
}

Event System

Components use emit(event) to fire events, or on(event) for metadata (shouldPreventDefault, bound).

Streaming

useUIStream and useChatUI return Vue Refs for streaming specs from an API.

BaseComponentProps

For catalog-agnostic reusable components:

import type { BaseComponentProps } from "@json-render/vue";

const Card = ({ props, children }: BaseComponentProps<{ title?: string }>) =>
  h("div", null, [props.title, children]);

Key Exports

| Export | Purpose |

|--------|---------|

| defineRegistry | Create a type-safe component registry from a catalog |

| Renderer | Render a spec using a registry |

| schema | Element tree schema (from @json-render/vue/schema) |

| StateProvider, ActionProvider, VisibilityProvider, ValidationProvider | Context providers |

| useStateStore, useStateValue, useBoundProp | State composables |

| useActions, useAction | Action composables |

| useFieldValidation, useIsVisible | Validation and visibility |

| useUIStream, useChatUI | Streaming composables |

| createStateStore | Create in-memory StateStore |

| BaseComponentProps | Catalog-agnostic component props type |

How to use it

Copy the folder

Take vercel-labs/vue from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npm. Without those the skill loads but fails at the first command.