Borders define the edge; Radii define the corner shape. A border preset combines width, style and color. A radius preset defines corner rounding. Either can include a responsive progression, but neither has to change with viewport width. Standard CSS remains available for deliberate local exceptions.
Define borders and radii in the theme JSON. PostCSS, runtime theme generation and the preview use the same compiler and responsive resolver. Both plain CSS values and responsive progressions are supported.
Pass the effective theme JSON to the build and runtime. Legacy @theme definitions remain supported when included in the same compilation; JSON entries override matching legacy entries. Definitions from another compilation no longer leak through a process-global cache. The shared module owns defaults; generated compatibility files are postcss-uxdsl/theme/default-borders.uxdsl and postcss-uxdsl/theme/default-radii.uxdsl. Inspect the imported definitions instead of assuming a preset number is a pixel value.
{
"breakpoints": { "xs": 0, "md": 768 },
"radii": { "2": "xs(8px) md(12px)" },
"borders": { "1": "xs(1px solid #64748b) md(2px solid #64748b)" }
}This illustrative example uses xs: 0 and md: 768. It uses literal values to isolate the behavior; shared definitions can also reference configured Spacing and Palette tokens.
.card {
border: border(1);
border-radius: radius(2);
}.card {
border: 1px solid #64748b;
border-radius: 8px;
}
@media (min-width: 768px) {
.card {
border: 2px solid #64748b;
border-radius: 12px;
}
}Below 768px, the card has a 1px border and 8px corners. At 768px and above, it has a 2px border and 12px corners. The most recent applicable value persists until another rule overrides it. Reusing the presets on another component shares that progression. The component consumes variables such as --uxdsl__border__1 and --uxdsl__radius__2. Edit and rebuild the source theme, or replace the managed theme stylesheet through generateThemeCss(nextTheme), to update consumers. The plain CSS example isolates the equivalent visual behavior.
/* Assumes spacing 2/3 and palette primary.main are configured. */
@theme {
radius-2: xs(space(2)) md(space(3));
border-1: xs(1px solid palette(primary.main));
}Spacing supplies reusable measurements; Palette supplies a semantic color role. A 1px hairline can intentionally remain stable. Prefer Density for component spacing, but do not automatically apply Density to border widths or corner radii: choose the intended edge and shape behavior.
| Expression | Current compiler result |
|---|---|
radius(2) | The configured radius-2 preset |
radius(pill) | 9999px |
radius(full) | 9999px, the same as pill |
radius(circle) | 50%; a circle requires equal width and height |
rounded() is an alias of radius(). These keywords are built-in values, not references to editable numbered presets. Rounding a box does not itself clip overflowing child content.
.selected-card {
border: border(1);
border-color: palette(primary.main);
border-style: dashed;
border-radius: radius(2);
}Put explicit longhand overrides after the shorthand. The shared engine now changes the preset variable across breakpoints, rather than emitting a new shorthand in the component, so these local overrides persist. Currently, when a numbered Border preset exists, border(1, palette(primary.main), dashed) selects that complete preset and ignores the optional color/style arguments. Use the longhand form above for a deliberate local override.
Change a shared Border when all its consumers should change their edge. Change a shared Radius when all its consumers should change their corners. For one component, select another suitable existing preset or use explicit CSS. Preserve the reference instead of copying its current computed value.
The editor below reads the active theme and shared defaults. It generates scoped CSS and reports resolved token references using the same engine as PostCSS and runtime. Edits affect only this preview and do not save your source JSON. Invalid updates retain the last valid preview. Reset restores the active theme; resize the real browser to inspect transitions.
AI implementation guide
Responsibility: maintain shared edge treatments. Borders combine width, style and color. Components select a preset; Palette can preserve the semantic color dependency.
@theme definitions, configured breakpoints and referenced Spacing or Palette tokens before choosing a Border.border(n) preset when its complete treatment matches the intent. Do not interpret n as a pixel width.Decision rule: Choose a shared Border for a shared edge treatment. Use local longhands for intentional exceptions. Change the theme only for a shared change.
For “make only the selected card's border dashed,” retain its preset and add a local dashed style after it. The shared variable changes do not reset that longhand. Check its responsive widths and confirm unselected cards keep their existing style.
AI implementation guide
Responsibility: maintain shared corner shapes and their responsive behavior. Preserve intent, not just the current computed value.
radius-n theme definitions, breakpoints and any referenced Spacing tokens. Reuse an appropriate configured preset.radius(n) when a component belongs to the shared shape system. Do not substitute the value observed at one viewport.Decision rule: Choose a configured Radius for shared corner styling. Define its progression in the theme. Use native CSS for deliberate independent shapes.
For “make every card using radius-2 rounder on desktop,” inspect all consumers and the configured desktop threshold, update that preset's progression, rebuild and verify mobile, boundary widths and desktop. Keep components using radius(2).
Explore the browser preview below. Its local definitions and limitations are explained above.
Actual viewport: 0px. Resize the browser to test transitions. The preview uses the active theme and shared engine defaults. Edits below are scoped to this demo and do not save source JSON.
border: border(1);
1px solid var(--uxdsl__color__gray-300)border: border(2);
var(--uxdsl__space__1) solid var(--uxdsl__color__gray-300)border: border(3);
var(--uxdsl__space__2) solid var(--uxdsl__color__gray-400)border: border(4);
var(--uxdsl__space__3) solid var(--uxdsl__color__gray-500)border: border(5);
var(--uxdsl__space__4) solid var(--uxdsl__color__gray-600)border-radius: radius(0);
0border-radius: radius(1);
var(--uxdsl__space__1)border-radius: radius(2);
var(--uxdsl__space__2)border-radius: radius(3);
var(--uxdsl__space__3)border-radius: radius(4);
var(--uxdsl__space__4)border-radius: radius(5);
var(--uxdsl__space__6)radius(pill) → 9999pxradius(full) → 9999pxradius(circle) → 50%