Angular Tutorial
A step-by-step guide to using NYS Design System components in an Angular application.
Requirements: Angular >=20.0.0 (core, common, forms)
Installation
To start from scratch, install the Angular cli, and set up a new starter package:
Install the two NYSDS packages in your app folder:
@nysds/angularfor the Angular-wrapped components and@nysds/stylesfor the design tokens and global CSS.
Note: Both packages are versioned together. Always install matching versions to avoid token/component mismatches.
Project Setup
After installing, load the NYSDS styles to the styles array in your angular.json:
{
"projects": {
"my-angular-app": {
"architect": {
"build": {
"options": {
"styles": [
"node_modules/@nysds/styles/dist/nysds-full.min.css"
]
}
}
}
}
}
}
Usage
1. Standalone Components (Modern Angular)
In modern Angular (v14+), import individual NYSDS components directly into your standalone component's imports array and use them in your templates:
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!');
}
}
<nys-button
label="Submit"
variant="filled"
(nysClick)="handleSubmit()"
></nys-button>
2. Module-based Apps (NgModule)
If you're using an NgModule-based architecture, or want to import all components at once, import NysAngularModule into your app or feature module:
import { NgModule } from '@angular/core';
import { NysAngularModule } from '@nysds/angular';
@NgModule({
imports: [NysAngularModule]
})
export class AppModule {}
Forms
Our Angular components support ControlValueAccessor natively, so they work with both Template-driven forms and Reactive forms, including built-in form validation.
Template-driven forms
Use [(ngModel)] for two-way binding:
<nys-textinput
label="First name"
name="firstName"
[(ngModel)]="firstName"
></nys-textinput>
Reactive forms
Use formControlName:
<nys-textinput
label="First name"
name="firstName"
formControlName="firstName"
></nys-textinput>
Group controls
nys-checkboxgroup and nys-radiogroup bind at the group level, not on each individual checkbox or radio:
<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 validation, which is shown on blur.
To let Angular own validation instead, add the nysControlErrors directive. It subscribes to control.errors and sets the component's showError and errorMessage:
<nys-textinput
formControlName="email"
nysControlErrors
></nys-textinput>
Override the default error messages with the NYS_ERROR_MESSAGES provider:
providers: [
{
provide: NYS_ERROR_MESSAGES,
useValue: {
required: () => "Please fill in this field",
email: () => "Enter a valid email",
},
},
]
Inputs, Outputs, and Events
All properties are typed inputs and events are typed outputs:
<nys-textinput
[label]="'Email'"
[required]="true"
(nysChange)="onEmailChange($event)"
></nys-textinput>
Event detail is typed
onEmailChange(event: NysTextinputChangeEvent) {
console.log(event.detail.value); // autocompletes
}
Subpath Imports
To import individual components, use the per-component subpaths:
import { NysTextinputComponent } from "@nysds/angular/textinput";
import { NysCheckboxComponent } from "@nysds/angular/checkbox";
Server-Side Rendering
The components render client-side. If your app uses SSR, wrap containers in ngSkipHydration:
<div ngSkipHydration>
<nys-textinput></nys-textinput>
</div>
Or use provideClientHydration if registering components client-only.
What's next
You've covered the core patterns. From here, explore the full component library on the official NYSDS reference site, or browse the NYSDS Angular Demo repo.
Edit this page on GitHub (Permissions required)
Last updated: October 5, 2026