@nysds/angular
v1.22.0
Published
Angular components for the New York State Design System, generated from the NYSDS web components.
Readme
@nysds/angular
Angular components for the New York State Design System (NYSDS). Generated from the NYSDS web components library, with full support for template-driven forms, Reactive Forms, and Signal Forms.
Install
Setup a new Angular project
npm install -g @angular/cli
ng new my-angular-appInstall NYS Design System
npm install @nysds/angular @nysds/stylesPeer dependencies: Angular >=20.0.0 (core, common, forms).
Load styles
Add NYSDS styles to your angular.json:
{
"projects": {
"your-app": {
"architect": {
"build": {
"options": {
"styles": [
"node_modules/@nysds/styles/nysds-full.min.css"
]
}
}
}
}
}
}First component
Import standalone components directly into your component:
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NysButtonComponent } from '@nysds/angular';
@Component({
imports: [RouterOutlet, NysButtonComponent],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
protected readonly title = signal('my-angular-app');
handleSubmit() {
console.log('Button clicked!');
}
}NgModule support has been deprecated
Use "Standalone Components" instead.
Inputs, outputs, and two-way binding
All properties are typed inputs; events are typed outputs. No CUSTOM_ELEMENTS_SCHEMA needed:
<nys-textinput
[label]="'Email'"
[required]="true"
(nysChange)="onEmailChange($event)"
></nys-textinput>Event detail is typed:
onEmailChange(event: NysTextinputChangeEvent) {
console.log(event.detail.value); // autocompletes
}Signal Forms Known Limitations
When using Angular's Signal Forms with [formField], be aware of these constraints:
- name property overwrite: The
[formField]binding overwrites thenameattribute. This is an Angular Signal Forms limitation; there is no workaround on the component side. Use a different approach for form arrays that require distinct names. - pattern validation on empty array: Angular's Signal Forms passes an empty array for unset pattern metadata. The component defensively ignores these writes; no action needed on your side.
Forms
Template-driven forms
Use [(ngModel)] with form components:
<form>
<nys-textinput [(ngModel)]="email" name="email"></nys-textinput>
<nys-checkbox [(ngModel)]="agreed" name="agreed"></nys-checkbox>
</form>Reactive Forms
Use formControl or formControlName:
form = this.fb.group({
email: ["", [Validators.required, Validators.email]],
agreed: [false, Validators.required],
});<form [formGroup]="form">
<nys-textinput formControlName="email"></nys-textinput>
<nys-checkbox formControlName="agreed"></nys-checkbox>
</form>Signal Forms (Angular 21+)
Use [formField] with a form field definition:
email = signal<string>("");
emailControl = new FormControl<string>("", Validators.required);<nys-textinput [formField]="emailControl"></nys-textinput>Group controls
nys-checkboxgroup and nys-radiogroup bind at group level:
form = this.fb.group({
languages: [["en"], Validators.required],
});<nys-checkboxgroup formControlName="languages">
<nys-checkbox value="en">English</nys-checkbox>
<nys-checkbox value="es">Spanish</nys-checkbox>
</nys-checkboxgroup>Validation
By default, the component owns validation. Its required and pattern attributes drive ElementInternals validation, shown on blur.
To let Angular own validation instead, add the nysControlErrors directive:
<nys-textinput
formControlName="email"
nysControlErrors
></nys-textinput>The directive subscribes to control.errors and sets the component's showError and errorMessage. Override the default messages:
providers: [
{
provide: NYS_ERROR_MESSAGES,
useValue: {
required: () => "Please fill in this field",
email: () => "Enter a valid email",
},
},
]Disabled state
FormControl({ disabled: true }) disables the component:
control = new FormControl({ value: "", disabled: true });<nys-textinput [formControl]="control"></nys-textinput>Server-side rendering
The components render client-side. For SSR, wrap containers in ngSkipHydration:
<div ngSkipHydration>
<nys-textinput></nys-textinput>
</div>Or use provideClientHydration if registering components client-only.
Zoneless
The component outputs use Angular's output() function, which integrates with zoneless change detection. Zoneless apps work without extra configuration.
Subpath imports
Import individual components:
import { NysTextinputComponent } from "@nysds/angular/textinput";
import { NysCheckboxComponent } from "@nysds/angular/checkbox";License
MIT
