Skip to content

Design system and theming tools

Sixty-plus components and one theme per brand. The foundation under our newer systems.

Client
In-house
Status
Active
We built
Component library, charts, and theme tooling
A monthly bar and line chart of invoiced amounts, in the dark Nexus theme, with its data table below. Demo data.

Overview

The systems we build now stand on the same component library: more than sixty parts, from buttons and date pickers to data tables and a command palette, built once and reused in Nexus, Formula, and the property platform.

The challenge

The systems we build should wear the customer's brand, and we didn't want to rebuild buttons and tables for every new one.

What we built

A component library where the whole look comes from a theme, with keyboard navigation and reduced motion built in, plus tools to create and switch themes.

How it's used today

Nexus, Formula, and the property platform all run on it, each with a theme of its own.

The look lives in a theme, not in the components. Colours, corners, shadows, fonts, and how fast things move all sit in one theme file, with a light and a dark mode. Switch the theme and the same system wears your brand, without a single component being rewritten. The theme file is plain CSS, so it can even be swapped while the app is running.

For the people who sit in the system all day, it shows up in other ways. Tables can be sorted, filtered, and searched, charts take their colours from the same theme as everything else, and a single value makes the whole interface denser, with tighter spacing and smaller text, when a dashboard needs to fit more on the screen.

Everything works without a mouse. Every component has keyboard navigation and a visible focus, the command palette runs on the arrow keys, Home, End, and Enter, and screen readers get the right roles and labels. Anyone who has asked their computer for reduced motion doesn't get the animations.

For you, it means a new system doesn't start from scratch. It looks like yours from the first screen, and it works the same way as everything else we build on the library.

Try it

The same components, one theme at a time.

The sample here is real components from the library: a card, buttons, tabs, key figures and a chart. Pick a theme and they change their look, and the table below lists exactly which values changed. No component is rewritten.

Mode

Lasts until you close the tab. Only you see it.

The NIT.UI base package in NIT blue. Every app of ours starts here.

Body text contrast: 17.7:1. Muted text: 4.8:1.

This week's deliveries

Active

Three orders are waiting to be packed. The next truck leaves at two.

Welding Painting Assembly

Everything that belongs to the project, in one place.

On time %
96
Open cases
12

What changed 136 values

Source: NIT.UI-norinit-theme packages/themes/nit/tokens.css @ 374831e

NameNorin ITNIT
--accent #35312c #f4f4f5
--accent-foreground #ede6db #18181b
--background #0f0d0b #ffffff
--border #75564e #e4e4e7
--card #282420 #ffffff
--card-foreground #ede6db #18181b
--chart-1 #f97316 #3b82f6
--chart-2 #86b6dc #14b8a6
--chart-3 #e8b04a #f59e0b
--chart-4 #7cc48f #8b5cf6
--chart-5 #c79ab8 #ec4899
--chart-6 #827b72 #64748b
--chart-axis #c4bbae #71717a
--chart-cat-1 #f97316 #3b82f6
--chart-cat-10 #7cc48f #8b5cf6
--chart-cat-2 #86b6dc #14b8a6
--chart-cat-3 #e8b04a #f59e0b
--chart-cat-4 #7cc48f #8b5cf6
--chart-cat-5 #c79ab8 #ec4899
--chart-cat-6 #827b72 #64748b
--chart-cat-7 #f97316 #3b82f6
--chart-cat-8 #86b6dc #14b8a6
--chart-cat-9 #e8b04a #f59e0b
--chart-current #f97316 #3771d1
--chart-exempt #6b655e #aeaeb4
--chart-grid #75564e #e4e4e7
--chart-negative #f2735f #dc2626
--chart-other #d0d0d0 #373737
--chart-positive #7cc48f #16a34a
--chart-previous #6d6d6d #8a8a8a
--chart-projected #6e391a #a7c9ff
--chart-rank-1 #422516 #cee1ff
--chart-rank-2 #5e3119 #b5d1ff
--chart-rank-3 #7a3e1c #9ec3ff
--chart-rank-4 #994b1d #85b3fd
--chart-rank-5 #b7581d #6ea3fb
--chart-rank-6 #d9661b #5492f9
--chart-rank-7 #f97316 #3b82f6
--chart-ref-line #c4bbae #71717a
--chart-seq-1 #422516 #cee1ff
--chart-seq-2 #6c381b #a9caff
--chart-seq-3 #994b1d #85b3fd
--chart-seq-4 #c75e1c #629cfa
--chart-seq-5 #f97316 #3b82f6
--chart-text #c4bbae #71717a
--chart-volume #86b6dc #14b8a6
--destructive #f2735f #dc2626
--destructive-foreground #0f0d0b #ffffff
--destructive-soft-foreground #f2735f #dc2626
--foreground #ede6db #18181b
--info #86b6dc #3b82f6
--info-foreground #0f0d0b #ffffff
--info-soft-foreground #86b6dc #3b82f6
--input #827b72 #e4e4e7
--muted #191614 #f4f4f5
--muted-foreground #c4bbae #71717a
--muted-foreground-subtle #c4bbae #71717a
--popover #282420 #f4f4f5
--popover-foreground #ede6db #18181b
--primary #9a3412 #1c69e3
--primary-foreground #ede6db #f8f8f8
--primary-soft-foreground #f97316 #1c69e3
--ring #f97316 #1c69e3
--secondary #35312c #33548c
--secondary-foreground #ede6db #f8f8f8
--state-tile-bad-bg #450a0a #fef2f2
--state-tile-bad-foreground #fca5a5 #991b1b
--state-tile-brand-bg #1e120e #edf4fe
--state-tile-brand-foreground #f97316 #1c69e3
--state-tile-good-bg #052e16 #f0fdf4
--state-tile-good-foreground #86efac #166534
--state-tile-info-bg #172554 #eff6ff
--state-tile-info-foreground #93c5fd #1e40af
--state-tile-neutral-bg #191614 #f4f4f5
--state-tile-neutral-foreground #c4bbae #71717a
--state-tile-warning-bg #451a03 #fffbeb
--state-tile-warning-foreground #fcd34d #92400e
--state-tint-bad #f2735f #dc2626
--state-tint-brand #9a3412 #1c69e3
--state-tint-good #7cc48f #16a34a
--state-tint-info #86b6dc #3b82f6
--state-tint-neutral #c4bbae #71717a
--state-tint-warning #e8b04a #f59e0b
--success #7cc48f #16a34a
--success-foreground #0f0d0b #ffffff
--success-soft-foreground #7cc48f #16a34a
--warning #e8b04a #f59e0b
--warning-foreground #0f0d0b #18181b
--warning-soft-foreground #e8b04a #18181b
--font-family-display 'Newsreader Display', 'Newsreader Fallback', 'Georgia', serif ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'
--font-family-mono ui-monospace, 'Cascadia Code', 'Source Code Pro', 'Menlo', 'Consolas', monospace ui-monospace, 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', monospace
--font-family-sans 'Inter', 'Inter Fallback', sans-serif ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'
--font-family-special 'Inter', 'Inter Fallback', sans-serif ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'
--radius-alert 0 0.375rem
--radius-avatar 0 9999px
--radius-badge 0 9999px
--radius-btn 0 0.25rem
--radius-btn-pill 0 9999px
--radius-card 0 0.375rem
--radius-checkbox 0 0.125rem
--radius-chip 0 0.125rem
--radius-chip-pill 0 9999px
--radius-input 0 0.25rem
--radius-lg 0 0.375rem
--radius-md 0 0.25rem
--radius-modal 0 0.375rem
--radius-popover 0 0.375rem
--radius-progress 0 9999px
--radius-sm 0 0.125rem
--radius-switch 0 9999px
--radius-tooltip 0 0.25rem
--radius-xl 0 0.5rem
--radius-2xl 0 1rem
--duration-fast 0.2s 0.1s
--duration-normal 0.3s 0.15s
--duration-slow 0.5s 0.3s
--gradient-brand linear-gradient(rgb(154, 52, 18), rgb(154, 52, 18)) linear-gradient(oklch(0.55 0.2 260), oklch(0.55 0.2 260))
--hover-lift 0 -2px
--hover-scale 1 1.02
--shadow-2xl rgba(8, 6, 4, 0.65) 0px 32px 64px -20px rgba(0, 0, 0, 0.25) 0px 25px 50px -12px
--shadow-lg rgba(8, 6, 4, 0.55) 0px 12px 32px -12px rgba(0, 0, 0, 0.1) 0px 10px 15px -3px
--shadow-md none rgba(0, 0, 0, 0.1) 0px 4px 6px -1px
--shadow-sm none rgba(0, 0, 0, 0.05) 0px 1px 2px 0px
--shadow-xl rgba(8, 6, 4, 0.6) 0px 24px 48px -16px rgba(0, 0, 0, 0.1) 0px 20px 25px -5px
--norinit-brand-ink #f97316 #1c69e3
--norinit-brand-hover #b0400f #1c69e3
--norinit-brand-faint #9a341226 #1c69e326
--norinit-brand-soft #9a341266 #1c69e366
--norinit-brand-strong #9a3412a6 #1c69e3a6
--norinit-surface-low #35312c #f4f4f5
--norinit-outline #aa8984 #e4e4e7
--norinit-outline-dim #75564e #e4e4e7
--norinit-credit-color #f973168c #1c69e38c
--norinit-logo-shape #6e6e6e #71717a
--norinit-logo-shape-hover #8a8a8a #45454b
--norinit-logo-dot #4d4c4c #b8b8bd

The values come from the real theme files. Norin IT, NIT and Nexus are our own; CE Formula, Polarstigen, GnosjöBo and Gislatorp belong to clients and are shown with their permission.

How we built it

The components know nothing about colours or fonts. They read all of that from the theme, which is why the same button can look like Nexus in one system and like your brand in the next.

  1. One theme drives the look

    Colours, corners, shadows, fonts, and motion are tokens in one theme file, with light and dark modes. The components only ever point at the tokens, so a new brand is a new theme file and nothing else.

    Cards, badges, alerts, and the semantic colour tokens in the dark Nexus theme, all taken from the active theme.
  2. Themes switch at runtime

    The theme file is plain CSS that can be loaded while the app is running, with nothing to rebuild.

  3. Local themes

    Part of a page can get its own colours, for example a module in a colour of its own.

  4. Denser when it needs to be

    One value scales spacing and text size across the whole interface, or just one part of it. Corners, shadows, and lines stay as they are.

  5. Keyboard first

    Keyboard navigation, visible focus, and the right ARIA roles in every component, built to WCAG 2.1 AA. Animations switch off for anyone who has asked for reduced motion.

  6. Tables built for work

    Sorting, filtering, search, and paging in the data table, and long lists that stay smooth.

  7. Charts that follow the theme

    Time series, stacked bars, heatmaps, treemaps, and sparklines take their colours from the same tokens as everything else.

  8. The theme tool

    It reads the theme files, generates typed colours for the code, and works out whether text on each colour should be black or white to meet the contrast requirements.

  • SvelteKit
  • TypeScript
  • Tailwind CSS

Key metrics

Components in the library
60+
From buttons and date pickers to data tables, a command palette, and a number pad for PIN codes.
Theme file per look
1
Colours, corners, shadows, fonts, and motion, in a light and a dark mode.
Components rewritten for a new brand
0
A new brand gets a new theme. The components stay exactly as they are.
Contact

Got a system everyone's waiting on?

Tell us what you want to build and we'll take it from there.

Regarding: Design system and theming tools

All fields are required.

Next project

CE Formula One

Manufacturing · Real-time systems