page.mdx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { pageMetadata } from "@/lib/page-metadata"
  2. export const metadata = pageMetadata("docs/schemas")
  3. # Schemas
  4. Schemas define the structure and validation rules for your UI specs.
  5. ## What is a Schema?
  6. A schema defines the JSON structure that describes your UI. It includes:
  7. - **Element structure** — How components are nested and referenced
  8. - **Property types** — What props each component accepts
  9. - **Data binding syntax** — How to reference dynamic data
  10. - **Action format** — How user interactions are defined
  11. ## Schema-Agnostic by Design
  12. json-render can work with any JSON schema. `@json-render/core` provides the primitives to define catalogs and renderers for any format:
  13. - **@json-render/react** — The built-in flat element tree schema
  14. - **[A2UI](/docs/a2ui)** — Google's Agent-to-User Interaction protocol
  15. - **[Adaptive Cards](/docs/adaptive-cards)** — Microsoft's platform-agnostic UI format
  16. - **AG-UI** — CopilotKit's Agent User Interaction Protocol
  17. - **OpenAPI/Swagger** — API documentation schemas for dynamic forms
  18. - **Custom schemas** — Design your own format tailored to your domain
  19. See the [Custom Schema guide](/docs/custom-schema) to learn how to implement support for any schema.
  20. ## Built-in Schema
  21. `@json-render/react` uses a flat element tree schema with a root key and elements map:
  22. ```json
  23. {
  24. "root": "card-1",
  25. "elements": {
  26. "card-1": {
  27. "type": "Card",
  28. "props": { "title": "Dashboard" },
  29. "children": ["text-1", "button-1"]
  30. },
  31. "text-1": {
  32. "type": "Text",
  33. "props": { "content": { "$state": "/user/name" } },
  34. "children": []
  35. },
  36. "button-1": {
  37. "type": "Button",
  38. "props": { "label": "Click me" },
  39. "children": []
  40. }
  41. }
  42. }
  43. ```
  44. ## Schema Components
  45. ### Element Structure
  46. In the built-in schema, each element in the elements map has this structure:
  47. ```typescript
  48. interface Element {
  49. type: string; // Component type from catalog
  50. props: Record<string, any>; // Component properties
  51. children: string[]; // Array of child element keys
  52. visible?: VisibilityCondition; // Conditional display
  53. }
  54. ```
  55. ### Data Binding Syntax
  56. Reference dynamic data using `$state` expressions in props. The value is a JSON Pointer path into the state model:
  57. ```json
  58. {
  59. "type": "Text",
  60. "props": {
  61. "content": { "$state": "/user/name" },
  62. "count": { "$state": "/items/count" }
  63. },
  64. "children": []
  65. }
  66. ```
  67. json-render also supports `$item` and `$index` expressions for lists, two-way binding via `$bindState` / `$bindItem`, and conditional props. See [Data Binding](/docs/data-binding) for the full reference.
  68. ### Action Format
  69. Actions are defined in the catalog and referenced from components. The renderer handles action execution:
  70. ```typescript
  71. // In your catalog
  72. actions: {
  73. navigate: {
  74. params: z.object({ url: z.string() }),
  75. description: 'Navigate to a URL',
  76. },
  77. apiCall: {
  78. params: z.object({
  79. endpoint: z.string(),
  80. method: z.enum(['GET', 'POST', 'PUT', 'DELETE']),
  81. }),
  82. description: 'Make an API request',
  83. },
  84. }
  85. ```
  86. ## Custom Schemas
  87. `@json-render/core` is schema-agnostic. You can define any JSON structure:
  88. ```typescript
  89. import { z } from 'zod';
  90. // Define your own element schema
  91. const MyElementSchema = z.object({
  92. component: z.string(),
  93. settings: z.record(z.unknown()),
  94. nested: z.array(z.lazy(() => MyElementSchema)).optional(),
  95. });
  96. // Define your own data binding format
  97. const BoundValue = z.object({
  98. literal: z.string().optional(),
  99. source: z.string().optional(), // e.g., "/users/0/name"
  100. });
  101. // Define your own action format
  102. const ActionSchema = z.object({
  103. name: z.string(),
  104. context: z.record(z.unknown()).optional(),
  105. });
  106. ```
  107. ## Schema vs Catalog
  108. The schema and catalog work together but serve different purposes:
  109. - **Schema** — Defines the JSON structure (how elements are organized)
  110. - **Catalog** — Defines available components and their props (what can be used)
  111. The schema is the grammar; the catalog is the vocabulary.
  112. ## Next
  113. Learn about [specs](/docs/specs) — the actual JSON documents that describe your UI.