Viking-UI — The Zero-Dependency UI Kit
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.