page.mdx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. export const metadata = { title: "Validation" }
  2. # Validation
  3. Validate form inputs with built-in and custom functions.
  4. ## Built-in Validators
  5. json-render includes common validation functions:
  6. - `required` — Value must be non-empty
  7. - `email` — Valid email format
  8. - `minLength` — Minimum string length
  9. - `maxLength` — Maximum string length
  10. - `pattern` — Match a regex pattern
  11. - `min` — Minimum numeric value
  12. - `max` — Maximum numeric value
  13. ## Using Validation in JSON
  14. Use `{ "$bindState": "/path" }` on the value prop for two-way binding. Validation checks run against the value at the bound path (available as `bindings?.value` in components):
  15. ```json
  16. {
  17. "type": "TextField",
  18. "props": {
  19. "label": "Email",
  20. "value": { "$bindState": "/form/email" },
  21. "checks": [
  22. { "type": "required", "message": "Email is required" },
  23. { "type": "email", "message": "Invalid email format" }
  24. ],
  25. "validateOn": "blur"
  26. }
  27. }
  28. ```
  29. ## Validation with Parameters
  30. ```json
  31. {
  32. "type": "TextField",
  33. "props": {
  34. "label": "Password",
  35. "value": { "$bindState": "/form/password" },
  36. "checks": [
  37. { "type": "required", "message": "Password is required" },
  38. {
  39. "type": "minLength",
  40. "args": { "min": 8 },
  41. "message": "Password must be at least 8 characters"
  42. },
  43. {
  44. "type": "pattern",
  45. "args": { "pattern": "[A-Z]" },
  46. "message": "Must contain at least one uppercase letter"
  47. }
  48. ]
  49. }
  50. }
  51. ```
  52. ## Custom Validation Functions
  53. Define custom validators in your catalog's `functions` field. The catalog itself is framework-agnostic — only the `schema` import varies by platform:
  54. ```typescript
  55. import { defineCatalog } from '@json-render/core';
  56. import { schema } from '@json-render/react'; // or '@json-render/react-native'
  57. import { z } from 'zod';
  58. const catalog = defineCatalog(schema, {
  59. components: { /* ... */ },
  60. functions: {
  61. isValidPhone: {
  62. description: 'Validates phone number format',
  63. },
  64. isUniqueEmail: {
  65. description: 'Checks if email is not already registered',
  66. },
  67. },
  68. });
  69. ```
  70. ## Usage with React
  71. In `@json-render/react`, use `ValidationProvider` to supply implementations for your custom validators:
  72. ```tsx
  73. import { ValidationProvider } from '@json-render/react';
  74. function App() {
  75. const customValidators = {
  76. isValidPhone: (value) => {
  77. const phoneRegex = /^\+?[1-9]\d{1,14}$/;
  78. return phoneRegex.test(value);
  79. },
  80. isUniqueEmail: async (value) => {
  81. const response = await fetch(`/api/check-email?email=${value}`);
  82. const { available } = await response.json();
  83. return available;
  84. },
  85. };
  86. return (
  87. <ValidationProvider customFunctions={customValidators}>
  88. {/* Your UI */}
  89. </ValidationProvider>
  90. );
  91. }
  92. ```
  93. ### Using in Components
  94. The `useFieldValidation` and `useBoundProp` hooks wire validation into your registry components. Validation uses the path from `bindings?.value` (the bound state path):
  95. ```tsx
  96. import { useFieldValidation, useBoundProp } from '@json-render/react';
  97. function TextField({ props, bindings }) {
  98. const [value, setValue] = useBoundProp(props.value, bindings?.value);
  99. const { errors, isValid, validate, touch, clear } = useFieldValidation(
  100. bindings?.value ?? null,
  101. { checks: props.checks, validateOn: props.validateOn }
  102. );
  103. return (
  104. <div>
  105. <label>{props.label}</label>
  106. <input
  107. value={value || ''}
  108. onChange={(e) => setValue(e.target.value)}
  109. onBlur={() => validate()}
  110. />
  111. {errors.map((error, i) => (
  112. <p key={i} className="text-red-500 text-sm">{error}</p>
  113. ))}
  114. </div>
  115. );
  116. }
  117. ```
  118. See the [@json-render/react API reference](/docs/api/react) for full `ValidationProvider` and `useFieldValidation` documentation.
  119. ## Validation Timing
  120. Control when validation runs with `validateOn`:
  121. - `change` — Validate on every input change
  122. - `blur` — Validate when field loses focus
  123. - `submit` — Validate only on form submission
  124. ## Next
  125. Learn about [generation modes](/docs/generation-modes).