Troupe tokens

Input

A native <input> with its label, hint and error message in one HTML contract, wired with for and aria-describedby. No JavaScript. Switch the brand: nothing in the component changes, only the semantic tokens behind it.

Size

Default: data-size="md", which also applies when the attribute is missing. There are no variants in v1.

sm

Used only for the receipt.

md

Used only for the receipt.

lg

Used only for the receipt.

States

Hover and focus-visible come from :hover and :focus-visible; disabled from the native disabled attribute; invalid from aria-invalid="true", together with an error message linked by aria-describedby. The invalid cells are also required: the * after the label is drawn from the native required attribute.

Sizedefaulthoverfocus-visibledisabledinvalid
sm

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Include an @ and a domain.

md

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Include an @ and a domain.

lg

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Used only for the receipt.

Include an @ and a domain.

Point at itTab to itdisabledaria-invalid="true"

Same height as Button

The md field and the md button use the same padding steps, border width and line height, so they line up in a form row. The layout (align-items, gap) belongs to the page, not to either component.

Reduced motion

Border, background and text colour change between states with motion.duration.state-change. That is feedback, not movement, so it stays under prefers-reduced-motion: reduce. Input has no other motion (ADR 0003).

Usage

<link rel="stylesheet" href="@iahola/troupe-tokens/troupe.css">
<link rel="stylesheet" href="@iahola/troupe-components/input/styles.css">

<div class="troupe-input" data-size="md">
  <label class="troupe-input__label" for="email">Email address</label>
  <input class="troupe-input__control" id="email" name="email" type="email" required
         aria-invalid="true" aria-describedby="email-hint email-error">
  <p class="troupe-input__hint" id="email-hint">Used only for the receipt.</p>
  <p class="troupe-input__error" id="email-error">Include an @ and a domain.</p>
</div>

Full specification: packages/components/input/README.md.