UX-DSL
XS0px

Inputs

Shared field roles, responsive spacing and visual interaction states.

Shared field roles and visual states

Responsibility: maintain reusable field treatments and their responsive and interaction styles. A component chooses an Input role. The theme composes its Surface, overrides, caret, placeholder and state styles. HTML and application logic provide labels, editing behavior, validation and error messages.

Inputs build on Surfaces, Density, Radii, Palette, Borders and Shadows. Preserve intent, not just the current computed value: a field should remain connected to its configured role when its current color or padding happens to match a literal value.

Define a field role in the theme JSON

{
  "breakpoints": {
    "xs": 0,
    "md": 768
  },
  "inputs": {
    "search": {
      "surface": "outlined",
      "base": {
        "padding": "density(2)",
        "caret": "palette(primary.main)",
        "placeholder": "palette(neutral.dark)"
      },
      "states": {
        "focus": {
          "border": "1px solid palette(primary.main)"
        },
        "focusvisible": {
          "outline": "2px solid palette(primary.main)",
          "outline-offset": "2px"
        },
        "invalid": {
          "border": "2px solid palette(error.main)"
        },
        "disabled": {
          "opacity": "0.6"
        }
      }
    }
  }
}

This excerpt assumes those dependencies exist. Default roles are contained, outlined and underline. Custom roles inherit contained defaults; choose a configured Surface explicitly when needed. Partial base and state fields merge with defaults. A supplied value replaces the entire field, including its responsive progression.

.search-field { @ds-input(search); }
<label for="search">Search</label>
<input id="search" class="search-field" type="search"
       aria-describedby="search-help">
<p id="search-help">Enter a product name.</p>

The component preserves shared references

.search-field {
  padding: var(--uxdsl__input__search-base-padding);
  caret-color: var(--uxdsl__input__search-base-caret);
  /* Remaining container fields reference the selected Surface. */
}
.search-field::placeholder {
  color: var(--uxdsl__input__search-base-placeholder);
}
.search-field:focus {
  border: var(--uxdsl__input__search-focus-border);
}

Padding follows Density. Other fields can define their own progression, such as xs(shadow(1)) md(shadow(2)). Define a base value; the most recent applicable rule persists until another threshold overrides it. Update the JSON and rebuild, or replace managed theme CSS to update existing values. Adding or removing fields or changing a role's Surface requires regenerating component CSS too; the demo uses inputComponentCss for that step.

Tones, sizes and underline treatment

.email { @ds-input(outlined primary 2); }
.compact-search { @ds-input(underline); width: auto; }

An optional Palette family overrides the Surface colors. Default caret and focus treatments follow that tone when the effective theme supplies the Palette family; explicit Palette assignments retain their meaning. Invalid defaults keep the error role. Pass the same effective theme to build and runtime. A numeric size selects Density and Radius keys, not pixels. Explicit Input base fields override the Surface composition, including tone and size.

The underline role uses the flat Surface and explicitly removes full borders and shadows, then applies underline as border-bottom. In custom roles, underline changes only the bottom border; add border: none in the base when bottom-only treatment is intended.

Supported fields: padding, radius, bg, color, border, shadow, caret, placeholder, underline, opacity, outline, outline-offset, transform, cursor and font-weight. Placeholder becomes a separate ::placeholder rule, including inside states. Supported states: hover, focus, focusvisible, readonly, invalid and disabled.

Styling and form behavior have distinct responsibilities

  • Use visible labels and appropriate native input types. Placeholder text does not replace a label. Associate help and error messages using aria-describedby.
  • Invalid styling matches native :invalid or aria-invalid=true. Native :invalid may match before interaction; the application controls when to show custom validation errors.
  • Disabled styling matches :disabled or aria-disabled=true. The disabled attribute prevents editing; aria-disabled alone does not. Readonly styling uses :read-only; use the native readOnly attribute on supported controls.
  • The engine keeps native focus outlines, inherits typography, sets border-box sizing and defaults width to 100%. It does not remove native appearance. Use subsequent CSS for deliberate local layout changes.
  • This treatment targets text-like inputs and textareas. Selects need their native interaction checked; checkbox, radio, range and file controls need dedicated treatment. Do not apply this pack indiscriminately.
  • Verify keyboard focus, foreground and placeholder contrast, error communication and touch use. Palette names do not guarantee accessibility.

Legacy @theme remains supported

@theme {
  input-search: {
    @ds-surface(outlined);
    padding: density(2);
    placeholder: palette(neutral-dark);
    :focus { border: 1px solid palette(primary-main); }
    :invalid { border: 2px solid palette(error-main); }
  }
}
.search-field { @ds-input(search); }

JSON overrides matching legacy base and state fields, then defaults. Import legacy packs in each compilation; Input packs no longer leak through a global cache. PostCSS, runtime, inspection and this demo share the Input engine. Default files are generated from that engine. Undefined roles, unsupported fields and invalid responsive mappings fail clearly; inspect remaining dependencies and actual CSS too.

The demo applies scoped JSON changes without saving the source file. Invalid edits retain the last valid preview. Resize the actual viewport, use the keyboard and try native readonly and disabled controls.

Interactive Demo

Shared engine playground

Actual viewport: 0px. Resize the browser to test responsive values. Hover or focus a field with the keyboard to inspect configured states. Try typing; readonly and disabled use native attributes. JSON edits are scoped to this demo and do not save source files.

Visible label and help text remain separate from styling.

.field { @ds-input(contained); }
CSS from the shared engine
.field { box-sizing: border-box; font: inherit; width: 100%; 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); caret-color: var(--uxdsl__input__contained-base-caret); }
.field::placeholder { color: var(--uxdsl__input__contained-base-placeholder); }
.field:focus { border: var(--uxdsl__input__contained-focus-border); box-shadow: var(--uxdsl__input__contained-focus-shadow); }
.field:invalid, .field[aria-invalid="true"] { border: var(--uxdsl__input__contained-invalid-border); }
.field:disabled, .field[aria-disabled="true"] { color: var(--uxdsl__input__contained-disabled-color); opacity: var(--uxdsl__input__contained-disabled-opacity); }
{
  "--uxdsl__input__contained-base-caret": "var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__contained-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-primary-base-caret": "var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__contained-tone-primary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-secondary-base-caret": "var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__contained-tone-secondary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-surface-base-caret": "var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__contained-tone-surface-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-tertiary-base-caret": "var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__contained-tone-tertiary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-success-base-caret": "var(--uxdsl__palette__success-main)",
  "--uxdsl__input__contained-tone-success-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-info-base-caret": "var(--uxdsl__palette__info-main)",
  "--uxdsl__input__contained-tone-info-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-warning-base-caret": "var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__contained-tone-warning-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-error-base-caret": "var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-error-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-dark-base-caret": "var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__contained-tone-dark-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-neutral-base-caret": "var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__contained-tone-neutral-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-light-base-caret": "var(--uxdsl__palette__light-main)",
  "--uxdsl__input__contained-tone-light-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-focus-border": "1px solid var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__contained-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-primary-focus-border": "1px solid var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__contained-tone-primary-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-secondary-focus-border": "1px solid var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__contained-tone-secondary-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-surface-focus-border": "1px solid var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__contained-tone-surface-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-tertiary-focus-border": "1px solid var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__contained-tone-tertiary-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-success-focus-border": "1px solid var(--uxdsl__palette__success-main)",
  "--uxdsl__input__contained-tone-success-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-info-focus-border": "1px solid var(--uxdsl__palette__info-main)",
  "--uxdsl__input__contained-tone-info-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-warning-focus-border": "1px solid var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__contained-tone-warning-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-error-focus-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-error-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-dark-focus-border": "1px solid var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__contained-tone-dark-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-neutral-focus-border": "1px solid var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__contained-tone-neutral-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-tone-light-focus-border": "1px solid var(--uxdsl__palette__light-main)",
  "--uxdsl__input__contained-tone-light-focus-shadow": "var(--uxdsl__shadow__2)",
  "--uxdsl__input__contained-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-primary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-secondary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-surface-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-tertiary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-success-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-info-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-warning-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-error-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-dark-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-neutral-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-tone-light-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__contained-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-primary-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-primary-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-secondary-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-secondary-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-surface-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-surface-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-tertiary-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-tertiary-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-success-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-success-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-info-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-info-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-warning-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-warning-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-error-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-error-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-dark-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-dark-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-neutral-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-neutral-disabled-opacity": "0.6",
  "--uxdsl__input__contained-tone-light-disabled-color": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__contained-tone-light-disabled-opacity": "0.6"
}

Visible label and help text remain separate from styling.

.field { @ds-input(outlined); }
CSS from the shared engine
.field { box-sizing: border-box; font: inherit; width: 100%; padding: var(--uxdsl__surface__outlined-padding); border-radius: var(--uxdsl__surface__outlined-radius); background: var(--uxdsl__surface__outlined-bg); color: var(--uxdsl__surface__outlined-color); border: var(--uxdsl__surface__outlined-border); box-shadow: var(--uxdsl__surface__outlined-shadow); caret-color: var(--uxdsl__input__outlined-base-caret); }
.field::placeholder { color: var(--uxdsl__input__outlined-base-placeholder); }
.field:focus { border: var(--uxdsl__input__outlined-focus-border); }
.field:invalid, .field[aria-invalid="true"] { border: var(--uxdsl__input__outlined-invalid-border); }
.field:disabled, .field[aria-disabled="true"] { opacity: var(--uxdsl__input__outlined-disabled-opacity); }
{
  "--uxdsl__input__outlined-base-caret": "var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__outlined-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-primary-base-caret": "var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__outlined-tone-primary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-secondary-base-caret": "var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__outlined-tone-secondary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-surface-base-caret": "var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__outlined-tone-surface-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-tertiary-base-caret": "var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__outlined-tone-tertiary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-success-base-caret": "var(--uxdsl__palette__success-main)",
  "--uxdsl__input__outlined-tone-success-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-info-base-caret": "var(--uxdsl__palette__info-main)",
  "--uxdsl__input__outlined-tone-info-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-warning-base-caret": "var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__outlined-tone-warning-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-error-base-caret": "var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-error-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-dark-base-caret": "var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__outlined-tone-dark-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-neutral-base-caret": "var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__outlined-tone-neutral-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-tone-light-base-caret": "var(--uxdsl__palette__light-main)",
  "--uxdsl__input__outlined-tone-light-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__outlined-focus-border": "1px solid var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__outlined-tone-primary-focus-border": "1px solid var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__outlined-tone-secondary-focus-border": "1px solid var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__outlined-tone-surface-focus-border": "1px solid var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__outlined-tone-tertiary-focus-border": "1px solid var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__outlined-tone-success-focus-border": "1px solid var(--uxdsl__palette__success-main)",
  "--uxdsl__input__outlined-tone-info-focus-border": "1px solid var(--uxdsl__palette__info-main)",
  "--uxdsl__input__outlined-tone-warning-focus-border": "1px solid var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__outlined-tone-error-focus-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-dark-focus-border": "1px solid var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__outlined-tone-neutral-focus-border": "1px solid var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__outlined-tone-light-focus-border": "1px solid var(--uxdsl__palette__light-main)",
  "--uxdsl__input__outlined-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-primary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-secondary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-surface-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-tertiary-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-success-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-info-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-warning-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-error-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-dark-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-neutral-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-tone-light-invalid-border": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__outlined-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-primary-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-secondary-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-surface-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-tertiary-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-success-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-info-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-warning-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-error-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-dark-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-neutral-disabled-opacity": "0.6",
  "--uxdsl__input__outlined-tone-light-disabled-opacity": "0.6"
}

Visible label and help text remain separate from styling.

.field { @ds-input(underline); }
CSS from the shared engine
.field { box-sizing: border-box; font: inherit; width: 100%; padding: var(--uxdsl__surface__flat-padding); border-radius: var(--uxdsl__surface__flat-radius); background: var(--uxdsl__surface__flat-bg); color: var(--uxdsl__surface__flat-color); border: var(--uxdsl__input__underline-base-border); box-shadow: var(--uxdsl__input__underline-base-shadow); border-bottom: var(--uxdsl__input__underline-base-underline); caret-color: var(--uxdsl__input__underline-base-caret); }
.field::placeholder { color: var(--uxdsl__input__underline-base-placeholder); }
.field:focus { border-bottom: var(--uxdsl__input__underline-focus-underline); }
.field:invalid, .field[aria-invalid="true"] { border-bottom: var(--uxdsl__input__underline-invalid-underline); }
.field:disabled, .field[aria-disabled="true"] { opacity: var(--uxdsl__input__underline-disabled-opacity); }
{
  "--uxdsl__input__underline-base-border": "none",
  "--uxdsl__input__underline-base-shadow": "none",
  "--uxdsl__input__underline-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-base-caret": "var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__underline-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-primary-base-border": "none",
  "--uxdsl__input__underline-tone-primary-base-shadow": "none",
  "--uxdsl__input__underline-tone-primary-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-primary-base-caret": "var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__underline-tone-primary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-secondary-base-border": "none",
  "--uxdsl__input__underline-tone-secondary-base-shadow": "none",
  "--uxdsl__input__underline-tone-secondary-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-secondary-base-caret": "var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__underline-tone-secondary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-surface-base-border": "none",
  "--uxdsl__input__underline-tone-surface-base-shadow": "none",
  "--uxdsl__input__underline-tone-surface-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-surface-base-caret": "var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__underline-tone-surface-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-tertiary-base-border": "none",
  "--uxdsl__input__underline-tone-tertiary-base-shadow": "none",
  "--uxdsl__input__underline-tone-tertiary-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-tertiary-base-caret": "var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__underline-tone-tertiary-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-success-base-border": "none",
  "--uxdsl__input__underline-tone-success-base-shadow": "none",
  "--uxdsl__input__underline-tone-success-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-success-base-caret": "var(--uxdsl__palette__success-main)",
  "--uxdsl__input__underline-tone-success-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-info-base-border": "none",
  "--uxdsl__input__underline-tone-info-base-shadow": "none",
  "--uxdsl__input__underline-tone-info-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-info-base-caret": "var(--uxdsl__palette__info-main)",
  "--uxdsl__input__underline-tone-info-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-warning-base-border": "none",
  "--uxdsl__input__underline-tone-warning-base-shadow": "none",
  "--uxdsl__input__underline-tone-warning-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-warning-base-caret": "var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__underline-tone-warning-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-error-base-border": "none",
  "--uxdsl__input__underline-tone-error-base-shadow": "none",
  "--uxdsl__input__underline-tone-error-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-error-base-caret": "var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-error-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-dark-base-border": "none",
  "--uxdsl__input__underline-tone-dark-base-shadow": "none",
  "--uxdsl__input__underline-tone-dark-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-dark-base-caret": "var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__underline-tone-dark-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-neutral-base-border": "none",
  "--uxdsl__input__underline-tone-neutral-base-shadow": "none",
  "--uxdsl__input__underline-tone-neutral-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-neutral-base-caret": "var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__underline-tone-neutral-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-light-base-border": "none",
  "--uxdsl__input__underline-tone-light-base-shadow": "none",
  "--uxdsl__input__underline-tone-light-base-underline": "1px solid var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-tone-light-base-caret": "var(--uxdsl__palette__light-main)",
  "--uxdsl__input__underline-tone-light-base-placeholder": "var(--uxdsl__palette__neutral-dark)",
  "--uxdsl__input__underline-focus-underline": "1px solid var(--uxdsl__input__tone-main, var(--uxdsl__palette__primary-main))",
  "--uxdsl__input__underline-tone-primary-focus-underline": "1px solid var(--uxdsl__palette__primary-main)",
  "--uxdsl__input__underline-tone-secondary-focus-underline": "1px solid var(--uxdsl__palette__secondary-main)",
  "--uxdsl__input__underline-tone-surface-focus-underline": "1px solid var(--uxdsl__palette__surface-main)",
  "--uxdsl__input__underline-tone-tertiary-focus-underline": "1px solid var(--uxdsl__palette__tertiary-main)",
  "--uxdsl__input__underline-tone-success-focus-underline": "1px solid var(--uxdsl__palette__success-main)",
  "--uxdsl__input__underline-tone-info-focus-underline": "1px solid var(--uxdsl__palette__info-main)",
  "--uxdsl__input__underline-tone-warning-focus-underline": "1px solid var(--uxdsl__palette__warning-main)",
  "--uxdsl__input__underline-tone-error-focus-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-dark-focus-underline": "1px solid var(--uxdsl__palette__dark-main)",
  "--uxdsl__input__underline-tone-neutral-focus-underline": "1px solid var(--uxdsl__palette__neutral-main)",
  "--uxdsl__input__underline-tone-light-focus-underline": "1px solid var(--uxdsl__palette__light-main)",
  "--uxdsl__input__underline-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-primary-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-secondary-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-surface-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-tertiary-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-success-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-info-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-warning-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-error-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-dark-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-neutral-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-tone-light-invalid-underline": "1px solid var(--uxdsl__palette__error-main)",
  "--uxdsl__input__underline-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-primary-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-secondary-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-surface-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-tertiary-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-success-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-info-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-warning-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-error-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-dark-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-neutral-disabled-opacity": "0.6",
  "--uxdsl__input__underline-tone-light-disabled-opacity": "0.6"
}

AI implementation guide

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, breakpoints and legacy imports 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.