For AI agents

How a coding agent should read and change a UXDSL project.

Point your agent at the guide that ships with the package

uxdsl ships its agent guide inside the package, at node_modules/uxdsl/docs/agent-guide.md, so it always describes the version the project has installed. Add one instruction to the project's own AGENTS.md (or the instruction file your agent reads), next to the project's own rules:

Before generating or modifying UXDSL UI, read
node_modules/uxdsl/docs/agent-guide.md and the active theme JSON.
Preserve configured roles and responsive behavior.

Adjust the path when node_modules is hoisted to a monorepo root. A link alone may not be fetched by every agent; a copy in the repository ages with every upgrade.

The one rule

Preserve intent, not just the current computed value. A component names a token or a role; the theme decides what it is and how it changes per breakpoint. Two declarations that compute to the same pixels today can mean different things tomorrow:

Do not replace……withbecause
density(4)space(4) or 0.75remthe density steps at each breakpoint; the space does not
palette(primary.main)color(purple.700) or a hexthe role follows a theme change and dark mode; a color does not
@ds-typo(h2)a fixed font-sizethe role's size and line height change per breakpoint
@ds-surface(contained)its six resolved propertiesthe role is shared; a copy is not

Before a change, decide its scope: one component (pick another existing token, or write a local CSS exception after the directive), a shared role or progression (edit the theme and check every consumer), or a threshold (edit breakpoints in the theme and rebuild). Never reference a token the theme does not define: the build fails with a UXD_* code, listed on Diagnostics.

Per primitive

Each block below is the guide for one primitive: what it is responsible for, how to choose it in a component, when to change the theme instead, and what to verify.

How an AI agent should use Spacing

UXDSL builds on standard CSS. Spacing defines the base spacing values, and Density makes that spacing responsive. Prefer Density for component spacing, use Spacing when a stable value is intentional, and use CSS directly when finer control is needed. This is the recommended authoring approach, not a compiler restriction.

When generating or modifying UI with UXDSL:

  • Inspect the active theme’s spacing definitions and existing component conventions before selecting tokens. Read densities and breakpoints when responsive behavior is required.
  • Treat space(n) as a configured token reference, not a pixel count or arithmetic multiplier. Do not infer values from another framework’s scale.
  • Prefer an existing token that matches the intended spacing. Do not reference undefined tokens; define a new token in the theme before using it when a system-level addition is needed.
  • Prefer an appropriate density(n) token for component spacing. Use space(n) directly when a stable value is intentional, and use CSS directly when finer control is required. Do not duplicate an existing Density progression locally.
  • Do not choose space(n) merely because it matches a Density token at the current breakpoint. Preserve the component’s intended responsive behavior.
  • If no Density token fits, inspect the theme and the requested scope before defining a system-level token or using a deliberate local exception. Never invent an undefined reference.
  • Choose padding for internal space, margin for external separation, and gap for spacing between items in a compatible layout.
  • Change a shared spacing value only when the intended change should affect all its consumers. Inspect direct references and Density mappings that depend on it.
  • For a local adjustment, select another appropriate token in the component. Use a deliberate local exception when the design requires behavior independent of shared tokens.
  • Edit source theme definitions or apply them at run time with applyTheme. Do not hand-edit generated CSS as the source of truth.
  • Account for the configured units. A stable rem value can have a different pixel size when the root font size changes; space() itself does not create breakpoint rules.
  • Verify affected padding, margins and gaps, check shared consumers for overflow or wrapping, and test relevant themes. If Density references the edited token, also check its breakpoint boundaries.

Decision rule: Prefer Density for component spacing. Use Spacing for intentional stable values and CSS for finer control. Change shared Spacing or Density definitions only for intentional system-level changes.

Example

Given this theme excerpt:

{
  "spacing": {
    "2": "0.25rem",
    "4": "0.75rem",
    "6": "1.5rem"
  }
}

For this deliberate exception, the card padding and actions gap must remain stable across breakpoints. Reuse the configured Spacing value:

.card {
  padding: space(4);
}
.actions {
  display: flex;
  gap: space(4);
}

Both references resolve to 0.75rem. Avoid replacing them with a hardcoded 0.75rem when they should remain connected to the theme.

Agent reasoning example

Make only this card’s padding smaller, and intentionally keep it stable across breakpoints using the application’s spacing scale.
  1. Inspect the card’s current token and the actual spacing values in the theme.
  2. Choose an appropriate smaller existing value; in this example, space(2) is smaller than space(4).
  3. Change the card to padding: space(2). Keep the shared value of spacing entry 4 intact because the request applies only to the card.
  4. Check the card’s content, wrapping and overflow, and confirm that the actions gap remains unchanged.

If the request instead changes spacing entry 4 across the system, update its theme value, apply or compile the theme, and verify both direct consumers and dependent Density mappings.

Choose the token in the component. Define its value in the theme.

How an AI agent should use Density

UXDSL builds on standard CSS. Spacing defines the base spacing values, and Density makes that spacing responsive. Prefer Density for component spacing, use Spacing when a stable value is intentional, and use CSS directly when finer control is needed. This is the recommended authoring approach, not a compiler restriction.

When generating or modifying UI with UXDSL:

  • Read the theme's spacing, densities, and breakpoints definitions before selecting spacing tokens.
  • Prefer existing design-system tokens over introducing new values, tokens, or responsive rules.
  • Prefer an appropriate density(n) token by default for component spacing.
  • Use space(n) directly when a stable value across breakpoints is intentional. Use CSS directly when finer control outside the configured Density behavior is required.
  • Do not replace Density with Spacing merely because their values match at one breakpoint. That would discard the intended responsive progression.
  • If no Density token fits, inspect the theme and requested scope before creating a system-level token or choosing a deliberate local exception. Never reference an undefined token.
  • Treat density(n) as a reference to a configured responsive spacing token. Never assume density(4) equals space(4) at every breakpoint.
  • Reuse existing Density tokens when their configured progression matches the intended behavior.
  • Do not reference undefined Density or Spacing tokens. When a new token is needed, define it in the theme before using it.
  • Do not reproduce a Density mapping locally with explicit breakpoint rules when an existing Density token already represents the intended behavior.
  • Change a Density mapping in the theme when the intended change should affect all consumers of that token.
  • Use a local component rule when the behavior is an intentional exception that should not affect the Density token or its other consumers.
  • Before creating a new Density token, check whether an existing token already provides the required responsive progression.
  • Verify the result just below, at, and just above each configured breakpoint where those widths are valid, and check other components consuming the same Density token.

Decision rule: Prefer Density for component spacing. Use Spacing for intentional stable values and CSS for finer control. Change shared Spacing or Density definitions only for intentional system-level changes.

Choose the token in the component. Define its responsive behavior in the theme.

Example

Given this example theme excerpt:

{
  "breakpoints": {
    "xs": 0,
    "md": 768,
    "xl": 1280
  },
  "spacing": {
    "4": "0.75rem",
    "5": "1rem",
    "6": "1.5rem"
  },
  "densities": {
    "4": "xs(space(4)) md(space(5)) xl(space(6))"
  }
}

When a component should follow that configured responsive progression, prefer:

.card {
  padding: density(4);
}

This resolves according to the theme:

  • Below 768px → space(4) → 0.75rem.
  • From 768px up to, but not including, 1280px → space(5) → 1rem.
  • 1280px and above → space(6) → 1.5rem.

Avoid recreating the same system behavior locally:

.card {
  padding: xs(space(4)) md(space(5)) xl(space(6));
}

The local form duplicates behavior already represented by density(4) and disconnects the component from future changes to that Density mapping. It still references the spacing scale.

Explicit local responsive spacing is valid when the component intentionally requires behavior that should remain independent from the configured Density mapping.

Agent reasoning example

If asked:

Make this card's padding follow the application's responsive spacing.

The agent should:

  1. Inspect the theme's available Density tokens.
  2. Find an existing Density progression that matches the requested behavior.
  3. Use that token in the component, for example padding: density(4).
  4. Avoid generating local breakpoint rules that duplicate the token's progression.
  5. Only create or modify a Density token when the requested behavior belongs at the design-system level.
  6. Verify the resulting behavior around every configured breakpoint and check affected consumers when the Density mapping changes.

The component declares which responsive spacing token it uses.

The theme defines how that token behaves across breakpoints.

How an AI agent should use Breakpoints

Breakpoints name the viewport widths where responsive rules begin to apply. The theme JSON defines the thresholds, components use those names for layout changes, and Density uses them to make Spacing responsive. Prefer Density for component spacing; use explicit breakpoint values for layout behavior and deliberate local exceptions.

Responsibility: preserve the shared responsive thresholds. Decide whether the request changes a component’s behavior, a Density mapping, or a system-wide threshold before editing configuration.

  • Read the actual theme’s breakpoints. Do not import values from another framework or infer device types from breakpoint names.
  • Use configured breakpoint names for explicit responsive layout changes. Define a base value when needed, and remember that the most recent applicable rule remains active until a rule at another configured breakpoint overrides it.
  • Prefer existing Density tokens for component spacing. Read their mappings before changing a breakpoint they depend on.
  • Change a shared threshold only when all affected responsive rules should move. For a local change, adjust the component’s responsive declarations using existing breakpoint names, or choose a deliberate local exception.
  • Do not replace Density with local breakpoint values just because their current computed values match. Preserve the intended system dependency.
  • Define required new thresholds through supported configuration before using them, and check support in the runtime and editor integrations. Do not assume all tools accept arbitrary names.
  • Keep source configuration aligned with compiler/runtime inputs. A browser-only override or manually edited generated CSS is not an update to the theme JSON.
  • Verify just below, at and just above affected thresholds, using valid nonnegative widths. Check intermediate inheritance, layout overflow, dependent Density rules and other shared consumers.

Decision rule: Change the component to change local behavior. Change a breakpoint to intentionally move a shared threshold. Change Density to adjust shared responsive spacing.

Configuration and usage example

{
  "breakpoints": {
    "xs": 0,
    "sm": 480,
    "md": 768,
    "lg": 1024,
    "xl": 1280
  }
}
.layout {
  display: flex;
  flex-direction: xs(column) md(row);
}
How this example keeps its most recent applicable value
Viewport widthflex-directionSupplying rule
Below 768pxcolumnxs(column)
From 768px up to, but not including, 1280pxrowmd(row) remains active through lg
1280px and aboverowmd(row) remains active unless a later rule overrides it

Agent reasoning example

Move the shared md transition to 800px across the application.
  1. Inspect the active configuration and confirm 800px fits between the intended neighboring thresholds.
  2. Find component rules and Density mappings referencing md. Confirm the request includes these consumers.
  3. Update breakpoints.md in the source JSON and apply it through the project’s build or runtime integration.
  4. Verify the column layout at 799px and row layout at 800px and 801px. Check Density transitions and consumers without an explicit md() rule.
  5. Check a later breakpoint to confirm the row value persists unless another declaration overrides it.

Breakpoints define when. Components and Density define what changes.

How an AI agent should use Colors

UXDSL builds on standard CSS. Colors define the available color values; Palette assigns colors to interface roles. Both are configured in the theme JSON. Prefer palette() when a component expresses a role such as primary action or surface. Use color() when a specific color token is intentional, and standard CSS when finer control is needed.

Responsibility: maintain the foundational color collection. Colors supply values to direct consumers and linked palette roles. Normally, semantic UI components consume Palette rather than selecting Colors directly.

  • Inspect colors and its families, shades and named entries. Treat shade numbers as keys, not calculated brightness or contrast guarantees.
  • Use color(token) directly only when a specific color identity is intentional, such as a swatch representing that token.
  • Before changing a Color value, trace direct color() consumers, CSS variable references and runtime links from Palette. Equal hex values alone do not establish a dependency.
  • Update the base Color only when all its direct and linked consumers are intended to receive the change. If the request concerns a UI role, reassign that Palette role instead.
  • Preserve explicit references from Palette to Colors. Do not replace them with copied hex values when the link should remain active.
  • Reuse existing Color tokens and define any required new token before referencing it. Do not create a duplicate merely to reproduce an existing value.
  • Edit the source JSON or apply it at run time with applyTheme. Do not hand-edit generated CSS as a second source of truth.
  • Verify direct swatches and linked roles after applying the change. Check active overrides, unrelated tokens and foreground/background pairs affected by the new base value.

Decision rule: Prefer Palette for semantic component styling. Use Colors directly only when a specific color identity is intentional. Modify a Color token only when its direct and linked consumers are intended to receive the change.

Preserve intent, not just the current computed value. A Palette role and a Color token can look identical today while responding differently to tomorrow’s theme changes.

Configuration and usage example

{
  "colors": {
    "blue": { "500": "#3b82f6", "700": "#1d4ed8" },
    "white": "#ffffff",
    "ink": "#0f172a"
  },
  "palette": {
    "primary": {
      "main": "color(blue.700)",
      "contrast": "color(white)"
    },
    "surface": {
      "main": "color(white)",
      "contrast": "color(ink)"
    }
  }
}
/* A swatch intentionally represents this Color token */
.blue-swatch {
  background: color(blue.700);
}

The swatch intentionally consumes blue-700 directly. In the JSON, primary.main also references that Color. Updating the Color changes both; reassigning the Palette role changes its consumers while the swatch keeps representing blue-700.

Agent reasoning example

Update blue-700 across the theme, including palette roles linked to it.
  1. Locate colors.blue["700"], its direct consumers, and palette references to it.
  2. Update the color value in the source JSON, preserving palette references rather than replacing them with copied hex values.
  3. Apply or compile the theme. Confirm that direct swatches and linked roles receive the new value.
  4. Check unrelated color tokens, literal palette values, relevant modes and foreground/background contrast.

Colors define the values. Palette defines their roles. Components express the intended use.

How an AI agent should use Palette

UXDSL builds on standard CSS. Colors define the available color values; Palette assigns colors to interface roles. Both are configured in the theme JSON. Prefer palette() when a component expresses a role such as primary action or surface. Use color() when a specific color token is intentional, and standard CSS when finer control is needed.

Responsibility: maintain the semantic roles consumed by UI components. Palette expresses purpose, such as primary action or surface, independently of the current color assigned to it.

  • Inspect palette, relevant mode overrides and component conventions before choosing a role and variant. Primary does not inherently mean blue.
  • Prefer palette(role.variant) when styling interface roles. Confirm the role, variant and any referenced Color exist in the intended theme.
  • Do not replace a Palette reference with a Color reference merely to reproduce the current visual result. Preserve the semantic layer when the component expresses a UI role.
  • Reassign a Palette role when its meaning stays the same but its visual color should change. Keep components connected to the role rather than rewriting their color declarations.
  • Use explicit CSS variable references in JSON when a role should follow a Color token. A literal color is independent; matching a Color token’s hex value does not link them.
  • For a change limited to one component, select an appropriate existing role or a deliberate local exception. Do not reassign a shared role unless its other consumers should change.
  • Update the Palette definition in the source theme or with an applyTheme patch. Review mode-specific assignments so they preserve the intended role.
  • Verify consumers of the reassigned role, interaction states and modes. Confirm direct Color consumers remain unchanged. Check the actual foreground/background contrast; the variant name contrast is not automatic validation.

Decision rule: Prefer Palette when styling interface roles. Reassign a Palette role when the meaning stays the same but its visual color should change. Keep components connected to the role.

Preserve intent, not just the current computed value. A Palette role and a Color token can look identical today while responding differently to tomorrow’s theme changes.

Configuration and usage example

{
  "colors": {
    "blue": { "500": "#3b82f6", "700": "#1d4ed8" },
    "white": "#ffffff",
    "ink": "#0f172a"
  },
  "palette": {
    "primary": {
      "main": "color(blue.700)",
      "contrast": "color(white)"
    },
    "surface": {
      "main": "color(white)",
      "contrast": "color(ink)"
    }
  }
}
.primary-action {
  background: palette(primary.main);
  color: palette(primary.contrast);
}

The action consumes primary.main, which currently references blue-700. Reassign the role to another defined Color to update its consumers while keeping their semantic declarations intact.

Agent reasoning example

Change primary actions to use the existing blue-500 color.
  1. Confirm blue-500 exists and inspect the primary role, its consumers and mode overrides.
  2. Update palette.primary.main to color(blue.500) in the intended theme scope.
  3. Keep components using palette(primary.main); leave direct blue-700 references unchanged.
  4. Apply the theme and verify affected actions, states and modes. Recheck the contrast foreground and adjust its definition if the design requires it.

Colors define the values. Palette defines their roles. Components express the intended use.

How an AI agent should use Typography

Responsibility: maintain shared text roles and their responsive behavior. Typography defines reusable visual text styles; components select the appropriate role without hardcoding the resolved values. HTML preserves document semantics.

Typography is the preferred shared abstraction for text styling. Preserve intent, not just the current computed value. Keep the configured role and its responsive behavior intact, just as you would preserve a Density token or a semantic Palette reference.

  • Inspect typography_details, its default fields, referenced fonts, spacing, and breakpoints before choosing or modifying a style. Treat these references as dependencies; inspect them without assuming they need to change.
  • Reuse an appropriate configured style with @ds-typo(role). Do not invent undefined roles or tokens.
  • Do not replace a Typography reference with a fixed font size merely because both look identical at the current breakpoint.
  • Keep semantic HTML appropriate to the document hierarchy; visual size does not determine the heading level.
  • Modify a shared style only when all its consumers should receive the change. Use a deliberate local rule for an isolated exception.
  • Preserve native CSS, units and token references when editing JSON. Do not convert unitless line height to pixels.
  • Use the shared generator and resolver. Do not recreate breakpoint parsing or write generated CSS as the source of truth.
  • Check just below, at and just above each configured breakpoint. Verify wrapping, zoom, font loading and other consumers of changed styles.

Decision rule: Choose the configured Typography role in the component. Define and evolve its visual and responsive behavior in the theme. Use local CSS only for intentional exceptions.

Example: preserve the shared role

.page-title {
  @ds-typo(h1);
}

The component selects the h1 typography role. The theme controls its font family, weight, line height, spacing references and responsive size progression.

Avoid copying the currently resolved values when the component is intended to remain connected to the shared Typography role:

.page-title {
  font-size: 2rem;
  line-height: 1.2;
}

These local values no longer follow changes to the shared role. They are appropriate only when that independence is an intentional exception.

Agent reasoning example

Make page titles follow the application’s responsive typography.
  1. Inspect the existing title styles and their responsive mappings.
  2. Choose the appropriate configured style, such as h1.
  3. Apply @ds-typo(h1) to the title selector while preserving appropriate HTML semantics.
  4. Verify the full progression instead of copying the font size visible on one screen.
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, 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. border() takes the preset key only: a second argument is UXD_EDGE_ARGUMENT.
  • 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.

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 the theme's radii 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 radius(pill) for the built-in 9999px treatment and radius(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).

How an AI agent should use Shadows

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

  • Inspect the effective shadows configuration, breakpoints and referenced color or spacing tokens before selecting a preset.
  • Reuse an appropriate configured shadow(key) for box shadows (the former elevation() alias fails as UXD_SYNTAX_REMOVED). Do not infer visual strength from a numeric key or confuse depth with z-index.
  • Preserve layers, nested color functions, inset flags, units and token references. Do not split shadow expressions with a simple comma-based parser.
  • Do not copy resolved shadow values into a component that should remain connected to a shared preset.
  • Change a shared preset only when all its consumers should follow. Select another preset or use native CSS for a deliberate local exception.
  • Define new presets before use. Unknown references are errors; check existing presets before adding a duplicate.
  • Use the shared generator and inspector for runtime and previews. Update source configuration rather than hand-editing generated CSS.
  • Verify just below, at and just above transitions, intermediate persistence, multiple consumers, states, themes, clipping, focus visibility and invalid-update recovery.

Decision rule: Choose the shared Shadow treatment in the component. Define its appearance and responsive progression in the theme. Use local CSS for intentional exceptions.

Agent reasoning example

For “make only this card less elevated,” inspect the actual preset values and choose an appropriate existing treatment for that card; leave the shared definition intact. For “soften shadow-2 across the product,” edit that preset, preserve its layers and references, apply the theme and inspect every affected consumer and breakpoint.

How an AI agent should use Surfaces

Responsibility: maintain shared container treatments by composing existing design-system roles and tokens. Preserve intent, not just the current computed value.

  • Inspect the effective surfaces configuration, breakpoints and referenced Density, Radii, Palette, Borders and Shadows before selecting a role.
  • Reuse a suitable configured role with @ds-surface(role). Do not rebuild its six properties locally merely because the result looks identical today.
  • Preserve token references. Surface radius references Radius, not Spacing; the Surface consumes that system's shape behavior.
  • Use a tone only when an explicit Palette-family override is intended. Check which fields it overrides for the selected variant.
  • Use the size argument only after checking both density(n) and radius(n). Do not infer measurements from the numeric key.
  • Change a shared Surface only when all its consumers should follow. Use a different role or subsequent local CSS for an intentional exception.
  • Partial overrides inherit missing fields; replacing a field replaces its full responsive expression. Custom roles inherit contained defaults.
  • Define roles and dependencies before use. Keep semantic HTML, layout and interaction behavior appropriate to the component.
  • Use the shared generator and inspector; update source configuration instead of generated CSS or demo-only default maps.
  • Verify breakpoint boundaries, intermediate persistence, nested containers, tone overrides, wrapping, border sizing, clipping, foreground contrast, focus visibility and all shared consumers.

Decision rule: Choose the container role in the component. Compose its shared visual decisions in the theme. Use optional arguments or native CSS only for deliberate overrides.

Agent reasoning example

For “make all contained cards less elevated on desktop,” inspect the contained role and its consumers, modify that role's shadow progression, apply the theme and verify each relevant breakpoint. Keep components using @ds-surface(contained). For one exceptional card, retain the role and override its shadow locally.

How an AI agent should use Buttons

Responsibility: preserve shared action roles and their visual states. Preserve intent, not just the current computed value.

  • Inspect buttons, surfaces, Palette, Density, Radii, Borders, Shadows and breakpoints before choosing a role.
  • Reuse a configured Button role. Do not replace its directive with currently resolved colors, padding or state styles.
  • Choose semantic HTML and implement activation, disabled and toggle behavior independently of styling.
  • Inspect inherited base and state fields. Define a custom role in JSON before referencing it. Explicit base fields override the selected Surface composition.
  • Use a tone or numeric size only for intentional overrides. Check Palette variants and both Density and Radius keys. Never infer pixels from a token number.
  • Change shared definitions only when their consumers should change. Select another role or use subsequent CSS for an isolated exception.
  • Keep responsive progressions in the theme and preserve their token dependencies. Include a base value and verify persistence between thresholds.
  • Update existing values through managed theme CSS; regenerate component CSS for structural changes to roles or state fields.
  • Verify hover, active, selected, disabled, keyboard focus, contrast, wrapping and breakpoint boundaries. Check other consumers of shared dependencies.

Decision rule: Choose the configured action role in the component. Maintain shared visual behavior in the theme; keep interaction semantics in HTML and application logic.

Agent reasoning example

For “increase the selected checkout action depth on desktop,” inspect the checkout role, change its selected shadow progression and verify all checkout consumers around each threshold. Keep their Button references. For one exceptional action, use a suitable existing role or intentional local CSS.

How an AI agent should use Inputs

Responsibility: preserve shared field roles and visual states while keeping form semantics in HTML and application logic. Preserve intent, not just the current computed value.

  • Inspect inputs, surfaces, referenced Density, Radius, Palette, Borders, Shadows and breakpoints before choosing or modifying a role.
  • Reuse a suitable configured role with @ds-input(role). Do not copy its current resolved colors, padding or focus treatment into local CSS.
  • Inspect inherited fields. Custom roles inherit contained defaults; explicit base fields override the selected Surface composition. Define a role and its dependencies before using it.
  • Use optional tones and sizes deliberately. Check the Palette family and both Density and Radius keys. Keep error styling connected to its error meaning.
  • Use labels, appropriate input types, native disabled/readOnly behavior and associated error messages. aria-invalid communicates an error; it does not validate the value.
  • Keep placeholder styling separate from labels. Preserve visible keyboard focus and check actual contrast and native interaction.
  • Modify shared role definitions only when all consumers should follow. Select another role or use subsequent local CSS for an isolated exception.
  • Generate successfully before replacing managed theme CSS. Regenerate component CSS when adding/removing fields or changing Surface selection. Preview edits do not save JSON.
  • Verify below, at and above configured breakpoints, intermediate persistence, focus, hover, invalid, disabled, readonly, placeholder states and every affected consumer.

Decision rule: Choose the configured field role in the component. Maintain shared visual behavior in the theme; implement validation and interaction semantics separately.

Agent reasoning example

For “make all search fields use a stronger error border,” inspect the search role and its consumers, change its invalid border in the theme, regenerate the needed CSS and verify native and aria-invalid states. Keep components using @ds-input(search). For one exceptional field, choose another role or deliberate local CSS.