Tutorial Angular

Componenti standalone Angular 20 — input a segnale, rilevamento delle modifiche OnPush, template inline, zero NgModule, zero CSS.

Cosa costruirai

Un piccolo modulo di contatto — campo con etichetta, pulsante di invio, binding bidirezionale, comportamento reale di tastiera e screen reader — prima spoglio, poi stilizzato, in circa 10 minuti.

Prima di iniziare

Servono git, Node 22 o successivo e pnpm 10 o successivo. Va bene qualsiasi progetto Angular 20 — Angular CLI o Analog.

Passo 1 — Ottieni il codice

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

I componenti sono file piatti in components/ — Button.ts, TextInput.ts — ognuno è un componente standalone con template inline, più il suo spec e la sua story. Il barrel index.ts riesporta ogni componente; pnpm build produce un bundle Angular Package Format tramite ng-packagr.

Passo 2 — Il tuo primo componente

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

Ogni componente dichiara un selettore lily-* e rende l'elemento semantico con il suo hook di classe — <button class="button" type="button"> qui. Gli input sono basati su segnali: label() per un aria-label per sostituire, className() per aggiungere classi.

Passo 3 — Componi un piccolo modulo

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 riceve l'etichetta visibile come proprio label input invece di un componente etichetta annidato — passala una sola volta, sul campo, e lily-text-inputcorrispondente label fornisce il nome accessibile. I componenti simili a input espongono valori model() quindi il banana-box [(value)] binding bidirezionale funziona subito — compatibile con zoneless ovunque.

Verificato il 2026-08-29: una bozza precedente annidava un componente Label separato dentro lily-field, che rendeva due etichette (una vuota) perché lily-field rende già la propria dall'input label — individuato controllando il sorgente del componente. La rotta composta del modulo di contatto è lo stesso schema, collaudato da veri test e2e e axe.

Controlla il lavoro: avvia l'app e il modulo appare spoglio — esattamente come previsto: lo stile deve ancora venire. Premi Tab: il focus si sposta su ogni controllo, l'etichetta viene annunciata e l'invio funziona. Il comportamento è fatto; l'aspetto è tuo, ed è il prossimo passo.

Passo 4 — Dagli uno stile

Stilizza gli hook di classe — .button, .text-input, .label, .field — in styles.css, oppure aggiungi un tema pronto all'array styles in angular.json / collegalo in index.html:

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

Passo 5 — Guarda tutto in funzione

App di esempio Angular + Analog mostra il catalogo completo con routing basato su file e Vite:

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

Prossimi passi

Domande lungo la strada? La pagina di aiuto è piena di risposte — e se un passo può essere più chiaro, faccelo sapere e miglioreremo volentieri il tutorial.