Skip to content
SENS Platform Docs

Frontend Design System

The web console uses repository-owned shadcn/ui components. Component source generated from the current shadcn registry stays inside the application, interactions use the component’s Radix primitives, and variants are explicit TypeScript APIs instead of copied class-name strings. The SENS semantic tokens and visual language remain authoritative. The system does not introduce a hosted service or a separate runtime.

The design system owns presentation and local interaction behavior. It does not make authorization decisions, infer tenant scope, or hide API errors. Product views still own their domain data, permissions, labels, and table columns.

Reusable code lives in:

  • apps/web-console/src/components/ui/ for small primitives and layout compositions;
  • apps/web-console/src/components/ui.tsx for domain-neutral feedback, overlays, icons, and existing compatibility exports;
  • apps/web-console/src/styles.css for semantic tokens and component styles;
  • apps/web-console/components.json for the shadcn CLI contract;
  • apps/web-console/src/components/design-system-showcase.tsx for the local component catalogue.

Only extract a component when the same intent occurs at least three times. Similar-looking elements with different operational meaning stay separate.

Token roleReference valueUsage
Signal Blue#1769FFPrimary actions, focus, current selection
Telemetry Teal#007F78Healthy telemetry and active signal paths
Control Navy#0B1724Navigation and high-contrast operational surfaces
Workspace Fog#F3F6F7Application background and quiet grouping
Warning Amber#A86400Recoverable warnings and incomplete states
Critical Red#B42332Destructive actions and failed states

Display headings use the condensed system stack, body copy uses the platform UI stack, and identifiers, timestamps, checksums, and telemetry values use the monospace stack. Monospace is not used merely as decoration.

Component familyImportPurpose
Buttoncomponents/ui/buttonSemantic variants, sizes, icons, disabled and busy states
Badgecomponents/ui/badgeCompact neutral, informational, success, warning, or danger labels
Input, Textareacomponents/ui/input, components/ui/textareaText entry with shared focus, validation, and disabled styling
Select, SimpleSelectcomponents/ui/selectRadix-backed option selection; SimpleSelect is the typed application composition
Checkbox, Labelcomponents/ui/checkbox, components/ui/labelAccessible binary input and explicit field labelling
Table familycomponents/ui/tableSemantic operational tables with bounded horizontal overflow
Tabs familycomponents/ui/tabsKeyboard-accessible switching between equal-level views and filters
Card, Alertcomponents/ui/card, components/ui/alertShared content and feedback surfaces used by application compositions
Dialog, AlertDialogcomponents/ui/dialog, components/ui/alert-dialogFocus, Escape, and modal semantics for overlays and confirmations
Sidebar familycomponents/ui/sidebarResponsive primary navigation backed by Sheet, Tooltip, Separator, and Skeleton primitives
AppSidebar compositionscomponents/app-sidebar, tenant-switcher, nav-main, nav-userOfficial collapsible sidebar-07 structure connected to scoped tenants, navigation, API status, and GET /v1/auth/me
Breadcrumb familycomponents/ui/breadcrumbAccessible Platform → tenant → current view context in the SidebarInset header
Skeleton, LoadingStatecomponents/ui/skeleton, components/ui.tsxShape-preserving loading feedback for navigation, pages, tables, and modal details
DataPanelcomponents/ui/layoutShared boundary for loading, empty, error, and tabular data
DataToolbar, InventoryToolbarcomponents/ui/layoutSearch, filter, and result-count compositions
TablePaginationcomponents/ui/layoutAccessible previous/next cursor navigation, current-page status, and bounded page-size selection
LoadMoreActionscomponents/ui/layoutProgressive cursor loading for non-tabular feeds and timelines
DialogActionscomponents/ui/layoutSticky modal footer with normal or split actions
EditorDialog, ConfirmDialogcomponents/ui.tsxCentered application modals over shadcn Dialog and Alert Dialog
StatusChip and feedback statescomponents/ui.tsxLoading, empty, success, status, and diagnostic error states

Import concrete component files where possible. Avoid a new application-wide barrel because it increases coupling and can make browser bundles harder to analyse.

The application shell follows a fresh shadcn sidebar-07 registry composition: SidebarProvider contains AppSidebar and SidebarInset; the sidebar header contains the controlled tenant switcher, the content contains role-filtered navigation, and the footer contains API status plus the current /me identity. The inset header uses the shadcn breadcrumb. Responsive, mobile-sheet, and collapsed behavior belongs to the shadcn primitive. Do not reproduce those states with breakpoint-specific width or visibility overrides.

Editing workflows use centered EditorDialog modals. They must not be styled as edge-attached drawers. Initial content loads use LoadingState skeletons whose shape reflects the surrounding page, table, or detail surface. Busy buttons remain explicit action progress indicators so their labels and layout do not disappear during a mutation.

Portal layers use one explicit stack: modal and mobile-sheet backdrops are at layer 80, their interactive content is at layer 90, and portalled Select, Dropdown Menu, and Tooltip content is at layer 100. A backdrop and its modal must never share the same layer; otherwise the backdrop can obscure the focused content in a browser stacking context.

Run the web console locally and open:

http://127.0.0.1:5173/design-system

The route exists only in Vite development mode. Production builds remove the catalogue branch, and the page is not part of product navigation or an authorization contract.

The application is configured for the shadcn CLI. A new component can be inspected with the current CLI and added from apps/web-console:

Terminal window
pnpm dlx shadcn@latest add <component>

Treat generated code as an editable starting point. Keep direct imports from the individual Radix packages instead of adding an aggregate runtime barrel. Before merging:

  1. map colors, radii, focus, and typography to existing semantic tokens;
  2. keep German product copy accurate and UTF-8 encoded;
  3. use Radix only for interactions that need its accessibility behavior;
  4. verify keyboard focus, Escape behavior, reduced motion, empty, error, loading, and disabled states;
  5. migrate all equivalent existing uses and remove superseded markup;
  6. add interaction tests and update this inventory.

Do not use the CLI to apply a preset over the existing theme. The visual world is specific to the SENS telemetry operating context and must not be replaced by a generic preset as a side effect of adding one component.

UI visibility is convenience only. platform-api remains the authorization boundary. Reusable components must receive already-scoped data and must not cache tenant-owned data, infer tenant identifiers, or turn disabled controls into authorization checks. Diagnostic components may render correlation IDs but never tokens, credentials, payload bytes, or cross-tenant details.

Radix overlay positioning and responsive layout variables require inline style attributes. The static server permits only that attribute-level behavior via style-src-attr 'unsafe-inline'. A per-response nonce authorizes the Radix scroll-lock style element; external style origins and inline scripts remain restricted by the rest of the Content Security Policy.

The Flow Studio mounts modal Dialog.Content only while Focus mode is active. Its ordinary workspace therefore remains in the accessibility tree without dialog semantics; opening traps focus inside the workspace, and Button or Escape closure restores focus to the focus-mode trigger button. Controlled graph state stays outside the modal wrapper so unsaved edits survive the transition.

For design-system changes, run the web-console typecheck, focused component and view tests, the production build, and the Impeccable detector. Verify the local catalogue at desktop and mobile widths. Changes to a domain workflow still need the tests required by that module in addition to these UI checks.