Skip to content

Form Schema

v0.2.8Формы и валидацияVueNuxt

Реактивные формы из декларативной схемы (JSON, Zod, Yup или Valibot) для Vue 3 — headless и SSR-совместимая альтернатива VeeValidate/FormKit.

Form Schema
Начать знакомство →
npm install @macrulez/vue-form-schema@latest
01 — Назначение

Когда это пригодится

Бэкенд уже описывает форму в JSON Schema, OpenAPI или Zod-типе — vue-form-schema превращает это описание прямо в рабочую форму на экране, вместо того чтобы вручную дублировать те же поля и правила валидации во Vue-компоненте.

Одни поля формы появляются в зависимости от других

Выбор «юрлицо» открывает поле ИНН, а «физлицо» — паспортные данные, и оба варианта нельзя показывать одновременно — форма сама решает, какие поля показать и провалидировать, в зависимости от того, что уже выбрал пользователь.

В форме нужен список из переменного числа строк

Список телефонов, позиций в счёте или участников команды — пользователь добавляет и удаляет строки сам, и каждая новая строка валидируется и очищается так же, как и первая.

Долгая форма разбита на несколько шагов

Анкета на десять экранов пугает, если показать её целиком, — форма делится на шаги с собственной проверкой каждого, и следующий шаг открывается только после того, как пройден предыдущий.

Сервер отклонил форму по причине, которую не проверяли на клиенте

Email уже занят — это можно узнать только после отправки на сервер. Ответ бэкенда раскладывается по нужным полям формы одним вызовом, и именно поле email подсвечивается красным, а не общее «что-то пошло не так» наверху.

02 — Фичи

Коротко о главном

Любой источник схемы — от JSON до Zod

Любой источник схемы — от JSON до Zod

Создавайте формы из FieldDefinition[], JSON, стандартной JSON Schema/OpenAPI, Zod, Yup или Valibot. Адаптеры для каждой библиотеки поставляются отдельными entry points, не раздувая основной бандл. Вывод типов (InferValues) работает автоматически для всех источников, давая полную типобезопасность.

Условные поля и динамические опции

Условные поля и динамические опции

Управляйте видимостью и доступностью полей через булевы значения, реактивные функции или строковые выражения. Опции select/radio могут быть синхронными или асинхронными с автоматическим перезапросом при изменении зависимостей (optionsDeps). Всё обновляется реактивно без лишних ререндеров.

Валидация и маскирование ввода

Валидация и маскирование ввода

Встроенные синхронные и асинхронные валидаторы (required, minLength, email, sameAs, fileType и другие) с режимами validateOn (input/blur/submit/eager) и validateMode (first/all). Маски ввода с пресетами (телефон, дата, IBAN, ИНН) и кастомными паттернами применяются автоматически.

Динамические массивы и многошаговые формы

Динамические массивы и многошаговые формы

useFieldArray даёт полный контроль над динамическими списками: append, prepend, remove, move, swap, replace. useMultiStepForm управляет пошаговыми формами с валидацией каждого шага и общим submit-обработчиком. Готовые рендереры (ArrayField, MultiStepFormRenderer) ускоряют разработку.

Headless, UI-темы и SSR-безопасность

Headless, UI-темы и SSR-безопасность

Core не зависит от UI — используйте любой дизайн через кастомные компоненты или реестр. Готовые рендереры для Tailwind, shadcn/ui, PrimeVue и Naive UI. SSR-безопасность, персистентность (local/sessionStorage), DevTools-инспектор и Nuxt-модуль с автоимпортами.

Композиция схем и серверные ошибки

Композиция схем и серверные ошибки

Собирайте большие формы из переиспользуемых частей через mergeSchemas, omitFields, pickFields и extendField — без дублирования полей между похожими формами. discriminatedFields подключает разные наборы полей по значению другого поля, а applyServerErrors раскладывает ответ бэкенда по полям формы одним вызовом.

03 — Быстрый пример

Как это работает

Схема из Zod — с типизацией из коробки

Разбираем обычную Zod-схему в поля формы через parseZod() — типы values выводятся из z.infer<> автоматически, без useForm<Values>().

zod-schema.ts
import { z } from 'zod'
import { parseZod } from '@macrulez/vue-form-schema/zod'
import { useForm } from '@macrulez/vue-form-schema'

const schema = z.object({
  name: z.string().min(2).describe('Full name'),
  age: z.number().min(0).optional(),
  email: z.string().email(),
  role: z.enum(['admin', 'user']),
})

const fields = parseZod(schema)
const { values } = useForm({ schema: fields })

// values.value.name is string, values.value.age is number | undefined, ...
// — inferred automatically from `schema` via z.infer<typeof schema>, no
// useForm<Values>(...) needed.

Поля, которые сами появляются и исчезают

visible принимает функцию от текущих значений — поле рендерится и валидируется только когда условие истинно, а clearOnHide сбрасывает его при скрытии.

conditional-fields.ts
import type { FieldDefinition } from '@macrulez/vue-form-schema'
import { useForm } from '@macrulez/vue-form-schema'

const schema: FieldDefinition[] = [
  { type: 'checkbox', name: 'hasCompany', label: 'I represent a company' },
  {
    type: 'text',
    name: 'companyName',
    label: 'Company name',
    visible: (values) => values['hasCompany'] === true,
    required: true,
  },
]

const { values } = useForm({ schema, clearOnHide: true })

Ошибки от бэкенда — сразу в нужные поля формы

applyServerErrors сам разбирает ответ Laravel/DRF (или любой формат через свой маппер) и раскладывает ошибки по полям — руками парсить ответ под каждый бэкенд не нужно.

server-errors.ts
import { applyServerErrors } from '@macrulez/vue-form-schema'

const res = await fetch('/api/users', { method: 'POST', body: JSON.stringify(form.values.value) })

if (!res.ok) {
  const { formErrors } = applyServerErrors(form, await res.json(), { format: 'laravel' })
  if (formErrors.length) toast.error(formErrors[0]) // errors not tied to a field
}

// Built-in formats: 'laravel', 'drf', 'flat' — or pass your own mapper.
// The next client-side validation naturally replaces a stale server error.