Design Systems
Install
Three steps, same as any Angular library — nothing framework-specific beyond that.
1. Install the package
npm install @nwds/ui2. Register the stylesheets
In
angular.json, order matters — tokens before base, base before your ownstyles.scss:"styles": [ "node_modules/@nwds/ui/styles/tokens.css", "node_modules/@nwds/ui/styles/base.css", "node_modules/@nwds/ui/styles/overlay.css", "src/styles.scss" ]3. Import and use a component
import { NwdsButton } from '@nwds/ui'; @Component({ imports: [NwdsButton], template: `<nwds-button variant="primary">Ship it</nwds-button>`, }) export class MyComponent {}
How the tokens are layered
One direction only: a primitive never appears directly in a component — everything routes through a semantic token first. Re-theming means changing layer 2, not hunting through every component. These are the real, live var(--nwds-*) values, not a static illustration.
1 · Primitives
2 · Semantic tokens
3 · Components
Button
Primary, secondary, and danger variants.
<nwds-button variant="primary">Primary</nwds-button>
<nwds-button variant="secondary">Secondary</nwds-button>
<nwds-button variant="danger">Danger</nwds-button>Card
A bordered, optionally elevated content container.
Elevated card
Content goes in the default slot.
<nwds-card [elevated]="true">
<h3>Elevated card</h3>
<p>Content goes in the default slot.</p>
</nwds-card>Badge
Status pills in every semantic variant.
<nwds-badge variant="success">Success</nwds-badge>Input
A labeled, form-ready text input (implements ControlValueAccessor).
<nwds-input label="Email" placeholder="you@company.com" />Avatar
Falls back to initials, then a generic icon, if the image fails to load.
<nwds-avatar name="Nihar Reddy" size="md" />StatCard
Used in the home page's metrics bar.
Years Experience
<nwds-stat-card label="Years Experience" value="12+" />MediaCard
Video tile with a play overlay, duration chip, and optional badge.
<nwds-media-card
thumbnail="..."
heading="Building Scalable Design Systems from Scratch"
category="Design Systems"
duration="42:18"
meta="48.2K views"
badgeLabel="Featured"
/>ProjectCard
Used for "Built with intent" on the home page — this very component is rendering that section right now.
NWDS UI
This design system.
<nwds-project-card
image="..."
category="Design System"
heading="NWDS UI"
description="This design system."
[tags]="['Angular', 'TypeScript']"
href="/portfolio/design-system"
[external]="false"
/>PostCard
featured shows an image + excerpt; compact is title-only.
Zero-Downtime Deployments
<nwds-post-card
variant="compact"
category="DevOps"
heading="Zero-Downtime Deployments"
date="Jun 29, 2026"
readTime="14 min read"
/>ThemeToggle
The same live instance as the one in the navbar — try it, both stay in sync via NwdsThemeService.
<nwds-theme-toggle />SearchMascot
The peek-a-boo search — click to open the panel.
<nwds-search-mascot placeholder="Search..." [categories]="searchCategories" />Mascot
The same character as the search bar, in all three moods it supports.
<nwds-mascot mood="wave" size="md" />
<nwds-mascot mood="dance" size="md" />
<nwds-mascot mood="cry" size="md" />MatchGame
Drag-and-drop matching engine, data-driven. Burst emoji on correct/incorrect are configurable.
Commands
What they do
<nwds-match-game
[pairs]="pairs"
[timeLimitSeconds]="60"
[correctEmoji]="['👏', '🎉']"
[incorrectEmoji]="['💨']"
(completed)="onComplete()"
(timedOut)="onTimedOut()"
/>ParticleBackground
The animated gold particle-mesh you're seeing right now, behind this entire page — it's position: fixed, mounted once globally in AppComponent, same reasoning as AccessibilityWidget below. Only draws in dark mode.
<nwds-particle-background />AccessibilityWidget
Text size, high contrast, and reduced motion controls. It's position: fixed to the viewport, so rather than duplicate it here, look at the bottom-right corner of this page — that's this same component, already mounted once, globally, in AppComponent.
<nwds-accessibility-widget />