Hướng dẫn Angular

Thành phần độc lập Angular 20 — signal input, phát hiện thay đổi OnPush, mẫu nội tuyến, không NgModule, không CSS.

Bạn sẽ xây dựng gì

Một biểu mẫu liên hệ nhỏ — ô nhập có nhãn, nút gửi, liên kết hai chiều, hành vi bàn phím và trình đọc màn hình thật — lúc đầu để trơn, sau đó thêm kiểu dáng, trong khoảng 10 phút.

Trước khi bắt đầu

Bạn cần git, Node 22 trở lên và pnpm 10 trở lên. Dự án Angular 20 nào cũng được — Angular CLI hoặc Analog.

Bước 1 — Lấy mã

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

Các thành phần là những tệp phẳng trong components/ — Button.ts, TextInput.ts — mỗi cái là một thành phần độc lập với mẫu nội tuyến, kèm spec và story của nó. Barrel index.ts xuất lại mọi thành phần; pnpm build tạo gói theo Angular Package Format qua ng-packagr.

Bước 2 — Thành phần đầu tiên của bạn

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"); }
}

Mỗi thành phần khai báo bộ chọn lily-* và hiển thị phần tử ngữ nghĩa với class hook của nó — <button class="button" type="button"> ở đây. Các đầu vào dựa trên signal: label() cho aria-label để ghi đè, className() để nối thêm lớp.

Bước 3 — Ghép một biểu mẫu nhỏ

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 nhận nhãn hiển thị làm label đầu vào riêng thay vì thành phần nhãn lồng bên trong — chỉ truyền một lần, ở trường, và lily-text-inputtương ứng label cung cấp tên có thể tiếp cận. Các thành phần giống ô nhập phơi bày giá trị model() nên banana-box [(value)] liên kết hai chiều hoạt động ngay — tương thích zoneless xuyên suốt.

Đã xác minh 2026-08-29: bản nháp trước lồng một thành phần Label riêng bên trong lily-field, khiến hiển thị hai nhãn (một cái rỗng) vì lily-field đã tự hiển thị nhãn của nó từ label đầu vào — phát hiện nhờ kiểm tra mã nguồn thành phần. Tuyến biểu mẫu liên hệ ghép sẵn cũng theo mẫu này, được kiểm chứng bằng các bài kiểm thử e2e và axe thật.

Kiểm tra kết quả: chạy ứng dụng và biểu mẫu trông trơ — đúng như dự định: kiểu dáng còn ở phía trước. Nhấn Tab: tiêu điểm di chuyển qua mọi điều khiển, nhãn được đọc lên và việc gửi hoạt động. Hành vi đã xong; diện mạo là của bạn và là bước tiếp theo.

Bước 4 — Tạo kiểu dáng

Tạo kiểu cho các class hook — .button, .text-input, .label, .field — trong styles.css, hoặc thêm một chủ đề dựng sẵn vào mảng styles trong angular.json / liên kết nó trong index.html:

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

Bước 5 — Xem mọi thứ hoạt động

Ứng dụng ví dụ Angular + Analog hiển thị toàn bộ danh mục với định tuyến theo tệp và Vite:

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

Các bước tiếp theo

Có thắc mắc trên đường đi? Trang trợ giúp có đầy câu trả lời — và nếu một bước có thể rõ ràng hơn, hãy cho chúng tôi biết và chúng tôi sẽ vui lòng cải thiện hướng dẫn.