Viking-UI — The Zero-Dependency UI Kit

Reading Progress89%

Chapter 31: Viking-UI — The Zero-Dependency UI Kit

The frontend design language of the platform is consolidated into a dedicated, workspace-local Angular library: @dataengineeringformachinelearning/viking-ui (frontend/projects/viking-ui). The kit ships native Angular standalone components with zero third-party UI runtime dependencies. Icons use an internal inline-SVG registry, charts render as native SVG paths, modals use the platform <dialog> element, and every color resolves through THEME.md semantic tokens — light/dark modes, the 4px grid, 16px main content typography, and 14px UI chrome are enforced by construction rather than convention. The library covers the full DEML component surface, from viking-button and viking-badge through viking-command, viking-editor, viking-kanban, viking-tabs, viking-table, and viking-toast.

Design philosophy (THEME.md)

Viking-UI expresses precision engineering and high-end industrial tech — see the canonical token matrix in THEME.md:

  • Dark-first engineering aesthetic — deep charcoals, machined metallic edges, no decorative noise.
  • Luxurious minimalism — every pixel earns its place; data and metrics dominate ornament.
  • Tactile surfaces — subtle top-edge highlights, restrained elevation, crisp borders.
  • Refined accent discipline — deep teal for primary action, rich crimson for secondary emphasis and danger.
  • WCAG 2.1 AA — contrast, focus rings, 44px mobile touch targets, keyboard navigation.

Every surface — dataengineeringformachinelearning.com, deml.app, Django templates, and Swagger UI — loads the same compiled viking-ui.css bundle synced from frontend/projects/viking-ui/src/styles/.

deml.app ships a marketing-parity landing page at /home (hero, capability bands, pricing, Polars-style whitepaper CTA) so the authenticated app feels cohesive with dataengineeringformachinelearning.com. Unauthenticated visitors hitting / are routed to /home; signed-in users go to /dashboard.

Consumption follows the path of least resistance. Inside the repository, deml.app imports @dataengineeringformachinelearning/viking-ui as a local npm package (file:dist/viking-ui, built via prebuild) while development can still resolve the library from source through the TypeScript path alias. Production pages consume Viking-UI components directly — buttons, fields, charts, modals, toasts, and selects — rather than hosting a component gallery on deml.app. Angular Material, ng-apexcharts, and @angular/cdk have been removed from the frontend; telemetry charts use native SVG viking-chart (line, bar, donut). The project is registered as an ng-packagr library in angular.json, so the same source produces a publishable Angular Package Format bundle. Components follow modern Angular idioms end-to-end: signal-based input()/model() APIs, OnPush change detection, and ControlValueAccessor implementations on every form control so both template-driven (ngModel) and reactive forms work out of the box. A separate Angular showcase app (projects/viking-ui-showcase) renders every component with realistic platform data for visual regression and contributor onboarding — build it with npm run build:viking-ui-system and deploy it independently of deml.app.

Non-Angular surfaces (marketing Astro pages, Django templates) load the static CSS bundle synced from the design system:

<link rel="stylesheet" href="/assets/design-tokens.css" />
<link rel="stylesheet" href="/assets/viking-ui.css" />
import {
  VikingButton,
  VikingCard,
  VikingToastService,
} from "@dataengineeringformachinelearning/viking-ui";

@Component({
  imports: [VikingButton, VikingCard],
  template: `
    <viking-card>
      <viking-button variant="primary" icon="check" (pressed)="save()"
        >Save</viking-button
      >
    </viking-card>
  `,
})
export class Example {
  private readonly toasts = inject(VikingToastService);
  save = (): void => void this.toasts.show({ text: "Saved.", tone: "success" });
}

Build

Run from the frontend/ workspace:

npm run test:viking-ui            # Vitest component tests (AnalogJS + axe patterns)
npm run build:viking-ui           # ng-packagr bundle → dist/viking-ui
npm run build:viking-ui-css       # Static CSS for marketing/backend templates
npm run build:viking-ui-showcase  # Optional component gallery app

Sync design tokens and viking-ui.css to marketing, backend, and frontend public assets:

python3 scripts/sync_design_system.py

The main Angular app rebuilds the library automatically via prebuild / prestart / pretest hooks.

Version bump

The published version lives in frontend/projects/viking-ui/package.json (currently read by ng-packagr into dist/viking-ui/package.json on build). Bump before every npm publish — npm rejects re-publishing an existing version.

Follow Semantic Versioning:

Bump When
patch Bug fixes, token/CSS tweaks, a11y fixes
minor New viking-* components, additive APIs
major Breaking changes to inputs, outputs, or removed exports
cd frontend/projects/viking-ui

# Choose one:
npm version patch --no-git-tag-version   # 1.0.0 → 1.0.1
npm version minor --no-git-tag-version   # 1.0.0 → 1.1.0
npm version major --no-git-tag-version   # 1.0.0 → 2.0.0

--no-git-tag-version updates only package.json (and package-lock.json if present in that folder); commit the bump with your release changes. After bumping, rebuild so dist/viking-ui carries the new version.

Publish to npm

Published scope: @dataengineeringformachinelearning (npm org dataengineeringformachinelearning). You must be a member of that org and use a 2FA one-time password when publishing.

cd frontend
npm run test:viking-ui
npm run build:viking-ui
cd dist/viking-ui
npm publish --access public --otp=YOUR_CODE

Install in downstream Angular apps:

npm install @dataengineeringformachinelearning/viking-ui

Peer dependencies: @angular/core, @angular/common, and @angular/forms ^22.

Quality & accessibility

The library carries a machine-readable manifest (viking.manifest.json) that maps each component to its Angular exports and the date of the last audit. The npm run check:viking-upstream script diffs manifest coverage and exits non-zero when the catalog drifts — surfacing gaps in CI the same way a failing contract test would. Accessibility is treated as a WCAG 2.1 AA / Section 508 contract: visible :focus-visible rings on every interactive element, full keyboard navigation for listboxes, menus and the command palette, role/aria-* semantics throughout, and prefers-reduced-motion handling on animated pieces such as skeletons and progress bars. The suite is verified by dedicated Vitest component tests (npm run test:viking-ui) that compile real templates through the AnalogJS Angular plugin, plus ng lint accessibility rules over the library's inline templates.