Connection lost. Reconnecting… attempt 1 of 8
Paused. Your work is held on the server.
Could not reconnect.
This session has expired on the server.
An unhandled error has occurred.
Sedna.UI
v0.17.0 · main

Concepts

this site, not the package

What decides how an app writes CSS against this library. Everything else on this site is markup to copy.

The two tiers

Tier 1 — the frame Shell, sidebar and nav, header, user widget, toasts, the modal shell. Pixel-identical in every app and never restyled per project.
Tier 2 — the paint Tables, forms, cards, badges, buttons, panels, alerts. Pages write plain HTML and apply the classes.

Both tiers are CSS classes. There is no <DataTable>, no <AppShell>, and there will not be either. The package ships the stylesheet, the script, the icons, the token export, and a small C# surface for what markup cannot express: which nav link is the current page, typed access to the browser API, and the service registration.

Cascade layers

The whole stylesheet is inside these layers, in this order. A later layer beats an earlier one regardless of specificity, which is why the reduced-motion block sits last.

LayerPart numbersWhat lives there
sedna.tokens00–04Tokens and the theme remap blocks
sedna.base05–09Bare elements — html, body, a, code, headings
sedna.frame10–29Tier 1
sedna.paint30–79Tier 2, then RTL, forced colours and print
sedna.utilities80–89Single-purpose classes
sedna.overrides90–99Density and reduced motion — the last word
Your stylesheet is unlayered, so it always wins Whatever the specificity. .card { padding: 12px } in your own file wins with no !important and no compound selector — and use no !important against the library either, because layer order inverts for important declarations and would make the rule harder to override. If a rule here has to be overridden to make something work, report it rather than out-specify it.

One control height

--control-height-sm (28px), --control-height (36px) and --control-height-lg (44px) are the height of everything that can sit in a row with another control: buttons, icon buttons, inputs, selects, the read-only value, the input group, the stepper, the search box and the chip.

Sizing a control yourself takes two rules Keep its own padding and line box under the tier, or the tier stops deciding anything and the control grows past it. And where a wrapper draws the border — an input group does — the wrapper takes the height and the children give theirs up.

The token contract

  • Every colour resolves through a token No hex, rgb() or colour keyword anywhere outside the token blocks. A test enforces it.
  • A theme is a token remap, never a selector override The light and colour-blind blocks contain values and no rules, which is why CSS load order does not affect them.
  • Redefine only names the library declares A new -- name risks colliding with a future token. Use an app-prefixed one until yours ships.
  • Some tokens are derived --brand-tint, the three rings and --brand-glow are mixed from --brand, so redefining it carries all five.

Naming

ShapeRule
.card, .btn-goSemantic, lowercase-kebab, no app or vendor prefix
.sedna-row, .sedna-scrollLibrary-owned utilities that need a namespace
.tab--activeA modifier is -- on the block
go, warn, danger, info, secretSemantic families, chosen by meaning across buttons, badges and alerts
cyan, orange, tealCategorical hues with no meaning at all
A plain name is a claim on the shared namespace An app that already styles .list or .menu silently gets both rule sets merged on upgrade — no error, just a changed appearance. Every release lists the class names it adds, so grep your own CSS before bumping.

Z-order

Shared by every app. Use one of these values for a new overlay — a test fails on any other. 0 to 3 are for local stacking inside a component and are not part of the scale.

Layerz-index
Topbar, floating action button60
User widget200
Collapsed-rail flyout400
Drawer scrim480
Drawer panel490
Modal backdrop500
Spotlight510
Popover, dropdown menu, search panel550
Toast600
Hover hints, reconnect banner1000
What the numbers do not say .topbar and .user-widget establish stacking contexts, so a panel nested in either is ordered within it and cannot be lifted above the modal backdrop by z-index alone. The top layer — anything promoted by popover or dialog.showModal() — ignores z-index entirely and orders by promotion. And the drawer sits below the modal backdrop on purpose, because a modal opened from inside a drawer has to cover it.

Direction and density

Every directional property in the library is a logical one, so the whole layout mirrors from dir="rtl" on <html>. Use the switch in the header to check any page on this site.

Write the logical property and it mirrors for free Write margin-inline-start, border-inline-end, inset-inline and text-align: start and your own pages mirror for free; only transform: translateX() and a background-position percentage have no logical form, and both are handled here. data-density="compact" tightens table cells, card padding and list rows by remapping --cell-pad-*, --card-pad-* and --list-pad-*; a component of your own that reads those tokens tightens with them.