UXDSL · CSS with a theme

Breakpoints belong to the theme, not to your components.

Spacing, type and color — and how each of them steps at a breakpoint — are defined once in a theme JSON. Components name them. The compiler writes the media queries and refuses any reference it cannot resolve.

The theme uxdsl.theme.json

{
  "densities": {
    "4": "xs(space(4)) md(space(5)) xl(space(6))"
  }
}

UXDSL you write card.uxdsl

.card {
  @ds-surface(contained);
  display: grid;
  padding: density(4);
  gap: xs(0.5rem) md(1rem);
}
.card h2 { @ds-typo(h2); }

CSS you get compiled by uxdsl

:root { --uxdsl__typography__h2-font-size: var(--uxdsl__space__6); }
@media (min-width: 480px) { :root { --uxdsl__typography__h2-font-size: var(--uxdsl__space__7); } }
@media (min-width: 1024px) { :root { --uxdsl__typography__h2-font-size: var(--uxdsl__space__8); } }
@media (min-width: 1280px) { :root { --uxdsl__typography__h2-font-size: var(--uxdsl__space__9); } }
:root { --uxdsl__density__4: var(--uxdsl__space__4); }
@media (min-width: 768px) { :root { --uxdsl__density__4: var(--uxdsl__space__5); } }
@media (min-width: 1280px) { :root { --uxdsl__density__4: var(--uxdsl__space__6); } }
.card {
  padding: var(--uxdsl__surface__contained-padding);
  border-radius: var(--uxdsl__surface__contained-radius);
  background: var(--uxdsl__surface__contained-bg);
  color: var(--uxdsl__surface__contained-color);
  border: var(--uxdsl__surface__contained-border);
  box-shadow: var(--uxdsl__surface__contained-shadow);
  display: grid;
  padding: var(--uxdsl__density__4);
  gap: 0.5rem;
}
@media (min-width: 768px) { .card { gap: 1rem; } }
.card h2 {
  font-family: var(--uxdsl__typography__h2-font-family);
  font-size: var(--uxdsl__typography__h2-font-size);
  line-height: var(--uxdsl__typography__h2-line-height);
  font-weight: var(--uxdsl__typography__h2-font-weight);
  letter-spacing: var(--uxdsl__typography__h2-letter-spacing);
  margin-block-start: var(--uxdsl__typography__h2-margin-block-start);
  margin-block-end: var(--uxdsl__typography__h2-margin-block-end);
}

Drag the frame's right edge (or the slider). The card has no breakpoint in it; its padding and title step at the theme's.

frame
390px
breakpoint
…
--uxdsl__density__4
…
h2 font-size
…

What the theme decides

Experiment: a theme from a name

Type a name and a language model writes a theme override for this site; it is validated and applied with applyTheme, like the header's theme buttons. It changes values only — the components are not rebuilt.