Skip to main content

Design system

Importing the neutron-design-system/styles.scss stylesheet makes your app look like it belongs in the Neutron shell. Its rules are narrow on purpose: dozens of independently authored apps should read as one system.

Setup

@use 'neutron-design-system/styles.scss';

@layer nt.tokens, nt.base, nt.layout, nt.components, nt.utilities, app;

@layer app {
.nt-app.my-app {
--nt-accent: #8adf9d;
}
}
<main class="nt-app nt-app--fill my-app">
<section class="nt-panel">
<h1 class="nt-title">My app</h1>
<button class="nt-button">Review in kernel</button>
</section>
</main>

Add a Sass plugin to your frontend build and link the generated CSS as a package-local asset from your HTML.

The package root separately exports optional TypeScript class helpers:

import {cx, nt, sizeClass, toneClass} from 'neutron-design-system';

They only compose class-name strings; importing them does not load the SCSS.

The rules

Rule
Dark onlyThere is no light theme
No gradients, no remote fonts
Radius capped at 5pxIn the public tokens
Separate by tonal fillNot by visible component borders
Structural separation = one-pixel inset hairlinesNot perimeter borders
Focus = a single visible hairline outline
Spacing follows 4/8/12/16/20/24/32px

And a compositional one that people miss:

Keep operational surfaces unframed on the page background. Do not turn every section into a card or panel.

Use nt-section headings, nt-detail-grid summaries, nt-settings-list rows, and nt-disclosure for secondary detail.

Scope and overrides

Everything is scoped under .nt-app and organised into cascade layers. Put your own rules in the app layer and use app-prefixed classes for local layout and composition.

Do not rewrite nt-* component classes, and never style kernel workspace classes from inside an app frame.

Recipes

App rootnt-app nt-app--fill plus an app-prefixed class.

A method call formnt-form-grid nt-form-grid--two for compact field pairs. Validate locally, show a request preview, then hand off with wording like Review in kernel.

Compact statusnt-metric, nt-metric-label, nt-metric-value, nt-metric-detail for non-interactive summaries.

Operational settingsnt-section with nt-detail-grid or nt-settings-list; nt-disclosure for secondary content, with its native button wired to aria-expanded and aria-controls.

Dense inspectorsnt-table-wrap, nt-copy-field, nt-json, nt-pre nt-pre--wrap.

Tagsnt-tag-list and nt-tag for compact metadata. If a tag is interactive, make it a button or checkbox.

Empty / loading / errornt-state variants and nt-alert with visible recovery controls.

Destructive flows — warning, danger, or critical severity with explicit consequence text. Kernel approval stays kernel-owned.

Accessibility

The package documents an accessibility matrix pairing each class with its element or role, name source, state attributes, and keyboard behaviour. Two points recur:

  • Tooltip text is not an accessible name. Icon buttons need aria-label or hidden text.
  • Native elements do the work. nt-button is a real <button>, nt-checkbox wraps a real input, nt-dialog is a native <dialog> or a named grouped panel with aria-labelledby.

role="alert" is for urgent inserted errors only, and aria-sort appears only when a table actually sorts. App code owns Escape handling and focus restore for its own dialogs.

The security rule

:::caution Do not imitate kernel dialogs App UI must not imitate the kernel's trusted approval, install, authorization, or signature dialogs.

An app frame cannot render into kernel chrome — whether it is an opaque tile or tray, or a capability-bound dedicated background — but it can draw something that looks like trusted UI. That is why the recommended wording for a consented action is deferential (Review in kernel): the app should visibly hand off, not appear to decide. :::

Reference

Kitchen Sink is the living reference and the package's test surface: forms, typed calls, schema display, alerts, warning and danger states, dense inspectors, and resize-heavy text in narrow tiles.

Tiles can be small. Test your layout at a narrow width in a split workspace, not just full-screen.