Use flikk's components
in your own projects.
The components we build for flikk, shipped the shadcn way. You run one command, the source lands in your app, and you own it from there. The first one is a JSON Schema builder.
npx shadcn@latest add https://oss.flikk.dev/ui/r/json-editor.jsonJSON Schema builder
You edit the schema as a tree and get valid JSON Schema back. Four presets, one set of parts.
Drag a row anywhere in the tree. Shift-click selects a range. On touch, long-press selects.
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"title": "ID",
"description": "Unique numeric identifier",
"examples": [
"1042"
]
},
"fullName": {
"type": "string",
"title": "Full name",
"description": "Display name shown in the app",
"examples": [
"Ada Lovelace"
]
},
"email": {
"type": "string",
"format": "email",
"title": "Email",
"description": "Primary contact address",
"examples": [
"ada@example.com"
]
},
"active": {
"type": "boolean",
"title": "Active",
"description": "Whether account can sign in",
"examples": [
"true"
]
},
"role": {
"type": "string",
"oneOf": [
{
"const": "admin",
"title": "Admin",
"description": "Full access"
},
{
"const": "editor",
"title": "Editor",
"description": "Can change content"
},
{
"const": "viewer",
"title": "Viewer",
"description": "Read only"
}
],
"title": "Role",
"description": "Permission level"
},
"address": {
"type": "object",
"properties": {
"street": {
"type": "string",
"title": "Street",
"examples": [
"12 Grimmauld Place"
]
},
"zip": {
"type": "string",
"title": "ZIP",
"description": "Postal code",
"examples": [
"10115"
]
}
},
"required": [
"street",
"zip"
],
"additionalProperties": false,
"title": "Address",
"description": "Postal address"
},
"tags": {
"type": "array",
"items": {
"type": "string",
"title": "Tags",
"description": "Free-form labels",
"examples": [
"vip"
]
},
"title": "Tags"
},
"contact": {
"oneOf": [
{
"type": "string",
"title": "Phone",
"description": "E.164 number",
"examples": [
"+41791234567"
]
},
{
"type": "object",
"properties": {
"network": {
"type": "string",
"oneOf": [
{
"const": "x",
"title": "X"
},
{
"const": "bluesky",
"title": "Bluesky"
}
],
"title": "Network"
},
"username": {
"type": "string",
"title": "Username",
"examples": [
"ada"
]
}
},
"required": [
"network",
"username"
],
"additionalProperties": false,
"title": "Social",
"description": "Network handle"
}
],
"title": "Contact",
"description": "How to reach them"
},
"createdAt": {
"type": "string",
"format": "date-time",
"title": "Created at",
"description": "When record was created",
"examples": [
"2026-09-14T10:00:00Z"
]
}
},
"required": [
"id",
"fullName",
"email",
"active",
"address",
"contact",
"createdAt"
],
"additionalProperties": false
}Three ways in
You choose how much of it you want to own.
import { JsonSchemaEditor, useJsonSchema } from "@/registry/base-nova/ui/json/editor"
function SchemaPage({ initial }) {
const schema = useJsonSchema(initial) // a handle; it never re-renders the owner
return (
<>
<JsonSchemaEditor schema={schema} variant="compact" />
<button onClick={() => save(schema.toJSON())}>Save</button>
</>
)
}You get real JSON Schema back
Draft 2020-12 in and out. Keywords the editor has no UI for stay on the field and come back untouched.
You drag any field anywhere
One model for the whole tree: a row to any depth, a group as one piece, a selection as a batch. A skeleton marks the slot, the siblings make room, and the row lands where the skeleton was.
You edit ten fields at once
Select with a click, shift-click for a range, or a long press on touch. Then toggle flags, move into a group, duplicate, or remove the lot.
You add your own types
A type is one object: icon, label, schema, example, what it accepts, its own extra UI. The editor picks it up; nothing inside branches on the type name.
You choose how deep to go
Ship the preset, compose the parts, or build your own rows on two hooks. The built-in parts are written on the same hooks.
You own the source
The shadcn way: the code lands in components/ui, styled from the tokens in your globals.css, built on Base UI. You edit it like anything else in your app.