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:

Copy Code
npm install -g @angular/cli
ng new my-angular-app

Install the two NYSDS packages in your app folder:

  • @nysds/angular for the Angular-wrapped components and
  • @nysds/styles for the design tokens and global CSS.

Note: Both packages are versioned together. Always install matching versions to avoid token/component mismatches.

Copy Code
npm install @nysds/angular @nysds/styles

Project Setup

After installing, load the NYSDS styles to the styles array in your angular.json:

Copy Code
{
  "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:

Copy Code
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!');
  }
}
Copy Code
<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:

Copy Code
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:

Copy Code
<nys-textinput
  label="First name"
  name="firstName"
  [(ngModel)]="firstName"
></nys-textinput>

Reactive forms

Use formControlName:

Copy Code
<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:

Copy Code
<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:

Copy Code
<nys-textinput
  formControlName="email"
  nysControlErrors
></nys-textinput>

Override the default error messages with the NYS_ERROR_MESSAGES provider:

Copy Code
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:

Copy Code
<nys-textinput
  [label]="'Email'"
  [required]="true"
  (nysChange)="onEmailChange($event)"
></nys-textinput>

Event detail is typed

Copy Code
onEmailChange(event: NysTextinputChangeEvent) {
  console.log(event.detail.value); // autocompletes
}

Subpath Imports

To import individual components, use the per-component subpaths:

Copy Code
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:

Copy Code
<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.