UX-DSL
XS0px

Borders & Radii

Shared edge treatments and corner shapes, with explicit responsive behavior.

Define shared edges and corners. Select them in components.

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.

Where these definitions live today

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.

One definition, multiple consumers

{
  "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.

UXDSL

.card {
  border: border(1);
  border-radius: radius(2);
}

Equivalent CSS behavior

.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.

Connect edges to the design system

/* 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.

Radius keywords

ExpressionCurrent 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.

A local exception should remain local

.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.

What the interactive demo changes

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

How an AI agent should use Borders

Responsibility: maintain shared edge treatments. Borders combine width, style and color. Components select a preset; Palette can preserve the semantic color dependency.

  • Inspect the effective theme JSON, any legacy @theme definitions, configured breakpoints and referenced Spacing or Palette tokens before choosing a Border.
  • Reuse an existing border(n) preset when its complete treatment matches the intent. Do not interpret n as a pixel width.
  • Do not replace a preset with its resolved shorthand merely because both look identical now.
  • For a local color or style exception, place CSS longhands after the Border declaration. Optional helper arguments do not override an existing preset.
  • Modify the shared definition only when all consumers should change. Trace dependent color and spacing tokens before changing foundational values.
  • Define new presets before use. Unknown references now report errors instead of silently inventing fallback values. Existing literal CSS values remain valid.
  • Rebuild and check breakpoint boundaries, box sizing, content area, layout shifts, states and edge contrast. Keep accessible focus indicators.

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.

Agent reasoning example

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

How an AI agent should use Radii

Responsibility: maintain shared corner shapes and their responsive behavior. Preserve intent, not just the current computed value.

  • Inspect radius-n theme definitions, breakpoints and any referenced Spacing tokens. Reuse an appropriate configured preset.
  • Keep radius(n) when a component belongs to the shared shape system. Do not substitute the value observed at one viewport.
  • Use pill/full for the built-in 9999px treatment and circle for 50%. Check dimensions; a rectangular box with 50% rounding is not a circle.
  • Change the shared Radius only when all its consumers should follow. Select another preset or use intentional per-corner CSS for a local exception.
  • The compiler rejects unknown radius references instead of inventing a fallback ramp. Define numbered presets explicitly and verify their dependencies.
  • Rebuild and inspect breakpoint boundaries, nested corners, images, overflow, focus outlines and different aspect ratios.

Decision rule: Choose a configured Radius for shared corner styling. Define its progression in the theme. Use native CSS for deliberate independent shapes.

Agent reasoning example

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).

Interactive Demo

Explore the browser preview below. Its local definitions and limitations are explained above.

Shared engine playground

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 presets

Border 1
border: border(1);
1px solid var(--uxdsl__color__gray-300)
Border 2
border: border(2);
var(--uxdsl__space__1) solid var(--uxdsl__color__gray-300)
Border 3
border: border(3);
var(--uxdsl__space__2) solid var(--uxdsl__color__gray-400)
Border 4
border: border(4);
var(--uxdsl__space__3) solid var(--uxdsl__color__gray-500)
Border 5
border: border(5);
var(--uxdsl__space__4) solid var(--uxdsl__color__gray-600)

Radius presets

Radius 0
border-radius: radius(0);
0
Radius 1
border-radius: radius(1);
var(--uxdsl__space__1)
Radius 2
border-radius: radius(2);
var(--uxdsl__space__2)
Radius 3
border-radius: radius(3);
var(--uxdsl__space__3)
Radius 4
border-radius: radius(4);
var(--uxdsl__space__4)
Radius 5
border-radius: radius(5);
var(--uxdsl__space__6)

Built-in shapes

pill
radius(pill) → 9999px
full
radius(full) → 9999px
circle
radius(circle) → 50%