Руководство по Vue

Однофайловые компоненты Vue 3 с типизированными props, defineModel двусторонней привязкой и пробросом v-bind="$attrs" .

Что вы построите

Небольшая контактная форма — поле с меткой, кнопка отправки, v-model привязка, реальное поведение клавиатуры и программы чтения с экрана — сначала голая, затем оформленная, примерно за 10 минут.

Прежде чем начать

Вам понадобятся git, Node 22 или новее и pnpm 10 или новее. Подойдёт любой проект Vue 3 — Nuxt, Vite или обычный Vue.

Шаг 1 — Получите код

git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-vue-headless
pnpm install
pnpm test        # vitest + @testing-library/vue
pnpm run storybook   # browse all 571 components

Компоненты — это плоские файлы в components/ — Button.vue, TextInput.vue — у каждого рядом его тест, story и документация. Скопируйте нужные файлы или подтяните репозиторий.

Шаг 2 — Ваш первый компонент

<script setup>
import Button from "lily-design-system-vue-headless/components/Button.vue";
</script>

<template>
  <Button @click="save">Save</Button>
</template>

Отображает <button class="button" type="button">. Props соответствуют другим фреймворкам: type, disabled, pressed, label, плюс проброс атрибутов для всего остального.

Шаг 3 — Составьте небольшую форму

<script setup>
import { ref } from "vue";
import Form from ".../components/Form.vue";
import Field from ".../components/Field.vue";
import TextInput from ".../components/TextInput.vue";
import Button from ".../components/Button.vue";

const name = ref("");
</script>

<template>
  <Form @submit="handleSubmit">
    <Field label="Full name" required>
      <TextInput id="name" label="Full name" v-model="name" required />
    </Field>
    <Button type="submit">Save</Button>
  </Form>
</template>

Field принимает видимую label как собственный prop, а не как вложенный компонент метки — передайте её один раз, на Fieldи TextInputиз label обеспечивает доступное имя.

Проверено 2026-08-29: в более раннем черновике отдельный компонент Label внутри Field, что отображало две метки (одну пустую), потому что Field уже отображает свою собственную из входа label prop — обнаружено компиляцией точного фрагмента. Маршрут Составной маршрут контактной формы — тот же шаблон, проверенный настоящими тестами e2e и axe.

TextInput использует defineModel, поэтому обычный v-model работает сразу.

Проверьте свою работу: запустите приложение, и форма выглядит голой — именно так, как задумано: оформление ещё впереди. Нажмите Tab: фокус проходит через каждый элемент управления, метка озвучивается, а отправка работает. Поведение готово; внешний вид за вами, и это следующий шаг.

Шаг 4 — Оформите её

Оформите крючки классов — .button, .text-input, .label, .field — в вашей таблице стилей, или подключите готовую тему в index.html / nuxt.config:

<link rel="stylesheet" href="/themes/nord.css" />

Шаг 5 — Посмотрите, как всё работает

Пример приложения Nuxt — это полный каталог в оформленном виде и с демонстрацией, с Playwright e2e и базовой линией axe-core:

git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-vue-nuxt-examples
pnpm install && pnpm run dev

Дальнейшие шаги

Есть вопросы по ходу дела? Страница справки полна ответов — а если какой-то шаг можно сделать яснее, сообщите нам и мы с радостью улучшим руководство.