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

Автономные компоненты Angular 20 — сигнальные входы, обнаружение изменений OnPush, встроенные шаблоны, ноль NgModules, ноль CSS.

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

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

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

Вам понадобятся git, Node 22 или новее и pnpm 10 или новее. Подойдёт любой проект Angular 20 — Angular CLI или Analog.

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

git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-angular-headless
pnpm install
pnpm test        # vitest + TestBed, all 571 components
pnpm run build-storybook

Компоненты — это плоские файлы в components/ — Button.ts, TextInput.ts — каждый является автономным компонентом со встроенным шаблоном, плюс его spec и story. Баррель index.ts реэкспортирует каждый компонент; pnpm build создаёт пакет в формате Angular Package Format через ng-packagr.

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

import { Component } from "@angular/core";
import { Button } from "@lilydesignsystem/angular-headless";

@Component({
  selector: "app-save-bar",
  standalone: true,
  imports: [Button],
  template: `<lily-button (click)="save()">Save</lily-button>`,
})
export class SaveBar {
  save() { console.log("saved"); }
}

Каждый компонент объявляет селектор lily-* и отображает семантический элемент со своим крючком класса — <button class="button" type="button"> здесь. Входы основаны на сигналах: label() для aria-label для переопределения, className() для добавления классов.

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

import { Component, signal } from "@angular/core";
import { Form, Field, TextInput, Button } from "@lilydesignsystem/angular-headless";

@Component({
  selector: "app-contact-form",
  standalone: true,
  imports: [Form, Field, TextInput, Button],
  template: `
    <lily-form label="Contact form" (submit)="handleSubmit($event)">
      <lily-field label="Full name" [required]="true">
        <lily-text-input id="name" label="Full name" [(value)]="name" />
      </lily-field>
      <lily-button type="submit">Save</lily-button>
    </lily-form>
  `,
})
export class ContactForm {
  name = signal("");
}

lily-field принимает видимую метку как собственный label вход, а не как вложенный компонент метки — передайте её один раз, на поле, и соответствующий lily-text-inputиз label обеспечивает доступное имя. Компоненты, похожие на поля ввода, предоставляют значения model() поэтому двусторонняя привязка banana-box [(value)] работает сразу — совместимо с zoneless во всём.

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

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

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

Оформите крючки классов — .button, .text-input, .label, .field — в styles.css, или добавьте готовую тему в массив styles в angular.json / подключите её в index.html:

<link rel="stylesheet" href="/themes/adobe-spectrum.css" />

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

Пример приложения Angular + Analog показывает полный каталог с файловой маршрутизацией и Vite:

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

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

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