Describe what you need, or type a control name.
Close Select Confirm

Build beautiful Angular apps, faster

65+ controlsEach one themed, tested and documented — no half-finished exports.
0 zonesNo zone.js in the bundle; signals drive change detection.
AA wcag 2.2Keyboard paths and axe checks run on every control in CI.
100% typedGeneric inputs, models and templates — no any, no string keys.
app.jig.awdlab.dev
Dashboard
Sales

Sales Overview

Revenue
$124,500
+12.5% vs last month
Active Leads
842
+45 new this week
Open Tasks
36
12 due today
Alerts
3
Requires attention

Recent Opportunities

CompanyValueStatusOwnerActions
ST Stark Tech
$1,250,000
Closed Won
JC Jane Cooper
WC Wayne Corp
$840,000
Negotiation
BW Bruce W.
TF TechFlow Inc
$12,400
Discovery
AS Alice S.
GX Globex
$96,000
Proposal
MR Mark R.
IN Initech
$38,500
Discovery
JC Jane Cooper
Rows: 1-5 of 24

Quick Add Deal

MMDDYYYYmonth, 1 to 12day, 1 to 31year, 0 to 9999
Pipeline by stage
  • Discovery1%
  • Proposal8%
  • Negotiation36%
  • Closed Won55%

Quick start

So simple to use

Import a control, bind your signal, ship. No boilerplate, no ceremony.

volume.component.ts

import { Component, signal } from '@angular/core';
import { JigSlider } from '@awdlab/jig/slider';
import { JigSwitch } from '@awdlab/jig/switch';

@Component({
  selector: 'app-volume',
  imports: [JigSlider, JigSwitch],
  template: `
    <jig-slider [min]="0" [max]="100" [(value)]="volume" />
    <jig-switch [(value)]="muted" />
  `,
})
export class VolumeComponent {
  protected readonly volume = signal(57);
  protected readonly muted = signal(true);
}
running here, zoneless live
57

No ngModel, no subscriptions, no change-detection calls — the signal is the binding.

Theming

Your design system, not ours

Every color, space and radius is a design token. Pick a theme and a color — every control follows.

Primary
Surface
Direction

live preview · Nova

Sign in

radius: … padding: … primary: … surface: …

Customization

Total control over every control

One list-box, four levels of control — open a level and watch the same control morph from a light restyle all the way to your own theme.

Developer experience

Your editor already knows the API

Typed inputs, models and events — discoverable without leaving the file. Switch between single and multiple selection: the control changes, and the value type changes with it.

Let users pick
one stage
value = "proposal"

deal-form.component.ts

type StageId = 'discovery' | 'proposal' | 'won';

@Component({
  imports: [JigInputField, JigSelect],
  template: `
    <jig-input-field label="Stage" labelKind="on">
      <jig-select
        [options]="stages"
        [(value)]="stage"
      />
    </jig-input-field>
  `,
})
export class DealFormComponent {
  stages: JigItem<unknown, StageId>[] = STAGES;
  stage = signal<StageId | null>(null);
}
100%

Typed public API

Inputs, models and outputs are generic — no any, no string keys, no guessing.

1

Import per control

Own entry point each, so only what you render reaches the bundle.

CI

Unit + visual tests

Screenshot regression and axe checks run on every control, every release.

i18n

Locale aware

Bundled UI translations; dates and numbers follow the active locale.

Accessibility

Drive it with the keyboard

Focus management, roving tabindex, ARIA state and live-region announcements ship with every control. The stage below is real library code, driven by the same key handling your users get.

keys the demo is pressing

Tab Home End Space
roving tabindex
Groups are one tab stop; arrows, Home and End move inside them.
focus return
Dialogs trap focus while open and hand it back to the trigger on close.
aria state
Checked, expanded, selected and disabled land on the real element, not a wrapper.
axe in CI
Every control is asserted against axe on every release, not audited once.

toolbar — one tab stop, arrows inside

Under the hood

Let the browser do it

Native where the platform is strong. Ours where it isn't — so you never wire it yourself.

platform native

Dialogs in the top layer

Opened with showModal(): focus trap, ::backdrop, Esc to close and correct stacking all come from the browser. No z-index wars, no portals.

platform native

Popovers, natively

Selects, menus and tooltips ride the Popover API — light dismiss, top-layer stacking and Shadow DOM support without an overlay engine.

we built it for you

Overflow that handles itself

Chips collapse into a counter and breadcrumbs fold into a menu — measured per container, not per viewport. No media queries. Drag the width down and watch.

Home
Workspace
Projects
Controls
Overview

we built it for you

Server-rendered, flash-free

Controls render fully styled on the server — your theme's colors and control styles are in the first byte, so there is no unstyled flash and no client round-trip. This page arrived that way.

<html> from the server

├ theme variables + control styles

├ real content, real ARIA, no JS

└ hydrates into the same DOM

Native dialog

This is a real <dialog> in the browser's top layer. Tab stays inside, Esc closes it, and focus returns to the button you came from.

Get started

Start with one control

Install, import, bind a signal — that is the whole learning curve. Swap in a single control where you need it and leave the rest of your app untouched, or point your coding agent at our MCP server and let it migrate the whole app in one pass. Your call.

MIT licensed · Angular 22+ · zoneless and signals-native