Angular-handledning
Fristående Angular 20-komponenter — signal-indata, OnPush-ändringsdetektering, inbäddade mallar, noll NgModules, noll CSS.
Det här bygger du
Ett litet kontaktformulär — fält med etikett, skicka-knapp, tvåvägsbindning, verkligt tangentbords- och skärmläsarbeteende — först naket, sedan formgivet, på ungefär 10 minuter.
Innan du börjar
Du behöver git, Node 22 eller senare och pnpm 10 eller senare. Alla Angular 20-projekt fungerar — Angular CLI eller Analog.
Steg 1 — Hämta koden
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
Komponenterna är platta filer i components/ —
Button.ts, TextInput.ts — var och en är en fristående komponent med inbäddad mall, plus sin spec och sin story. Barrel-filen
index.ts återexporterar varje komponent; pnpm build
skapar ett paket i Angular Package Format via ng-packagr.
Steg 2 — Din första komponent
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"); }
}
Varje komponent deklarerar en lily-* -selektor och renderar det semantiska elementet med sin klasskrok —
<button class="button" type="button"> här. Indata är signalbaserade: label() för en aria-label
för att åsidosätta, className() för att lägga till klasser.
Steg 3 — Sätt ihop ett litet formulär
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 tar den synliga etiketten som sin egen
label -indata i stället för en nästlad etikettkomponent — skicka den en gång, på fältet, så ger den matchande lily-text-inputfrån
label det tillgängliga namnet. Indataliknande komponenter exponerar model() -värden, så banana-box [(value)]
-tvåvägsbindning fungerar direkt — zoneless-kompatibelt rakt igenom.
Verifierat 2026-08-29: ett tidigare utkast nästlade en separat Label -komponent i lily-field, vilket renderar två etiketter (en tom) eftersom
lily-field redan renderar sin egen från
label -indata — upptäckt genom att granska komponentens källkod.
Den sammansatta kontaktformulärsrutten
är samma mönster, prövat med riktiga e2e- och axe-tester.
Kontrollera ditt arbete: kör appen så ser formuläret kargt ut — precis som tänkt: formgivningen återstår. Tryck på Tab: fokus flyttas genom varje kontroll, etiketten läses upp och inskickning fungerar. Beteendet är klart; utseendet är ditt och kommer härnäst.
Steg 4 — Formge det
Formge klasskrokarna — .button, .text-input,
.label, .field — i styles.css, eller lägg till ett färdigt tema i styles -arrayen i
angular.json / länka det i index.html:
<link rel="stylesheet" href="/themes/adobe-spectrum.css" />
Steg 5 — Se allt fungera
Exempelappen Angular + Analog visar hela katalogen med filbaserad routing och Vite:
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-angular-examples
pnpm install && pnpm run dev
Nästa steg
- Teman — byte under körning med Angular-hjälparen theme-picker.
- Inställningshjälpare — språk och textstorlek.
- Komponentkatalog — egenskaper, ARIA och tangentbord per komponent.
Frågor på vägen? Hjälpsidan är full av svar — och om ett steg kan bli tydligare, berätta för oss så förbättrar vi gärna handledningen.