Documentation
Forms
Input, Select, Textarea, Field
Text inputs, selects, text areas and native date and time pickers, with a Field wrapper that ties label, hint and error to the control, plus a spam-trap field.
components/input.css
Field
Wrap the control in a dsgn-field with a dsgn-label above it and an optional dsgn-hint below. Connect the hint with aria-describedby, so a screen reader reads it with the field.
We only use it for invoices.
<div class="dsgn-field">
<label class="dsgn-label" for="email">E-mail</label>
<input class="dsgn-input" id="email" type="email" autocomplete="email" aria-describedby="email-hint">
<p class="dsgn-hint" id="email-hint">We only use it for invoices.</p>
</div>Error
Set aria-invalid="true" on the control and give the hint data-intent="danger" with an icon. Say what is wrong and how to fix it, not only that something is wrong.
A company ID has 8 digits. This one has 4.
<div class="dsgn-field">
<label class="dsgn-label" for="ico">Company ID</label>
<input class="dsgn-input" id="ico" inputmode="numeric" value="1234" aria-invalid="true" aria-describedby="ico-error">
<p class="dsgn-hint" id="ico-error" data-intent="danger"><span class="dsgn-icon" aria-hidden="true">error</span>A company ID has 8 digits. This one has 4.</p>
</div>Text area
The same class on a <textarea>. It is three lines tall unless rows says otherwise.
<div class="dsgn-field">
<label class="dsgn-label" for="note">Note for the client</label>
<textarea class="dsgn-input" id="note"></textarea>
</div>With an icon
For an icon, the class moves to a wrapper and the control sits inside it. A control without a visible label needs an aria-label.
<div class="dsgn-input">
<span class="dsgn-icon" aria-hidden="true">search</span>
<input type="search" aria-label="Search invoices" placeholder="Search invoices">
</div>Select
A select is the same wrapper with a chevron after the native <select>.
<div class="dsgn-field">
<label class="dsgn-label" for="country">Country</label>
<div class="dsgn-input">
<select id="country">
<option>Czechia</option>
<option>Slovakia</option>
<option>Germany</option>
</select>
<span class="dsgn-icon" aria-hidden="true">expand_more</span>
</div>
</div>Date and time
Use the native control: type="date", time, datetime-local or month. The browser brings its own calendar, keyboard entry and the local date format, and the picker follows light and dark mode. For a range, put two date fields side by side, each with its own label.
<div class="dsgn-cluster">
<div class="dsgn-field">
<label class="dsgn-label" for="from">From</label>
<input class="dsgn-input" id="from" type="date" value="2026-11-01">
</div>
<div class="dsgn-field">
<label class="dsgn-label" for="to">To</label>
<input class="dsgn-input" id="to" type="date" value="2026-11-30">
</div>
</div>States
Hover, focus, aria-invalid="true", disabled and readonly are styled from the native state; there are no extra classes.
<div class="dsgn-grid" data-cols="1" data-cols-tablet="2">
<div class="dsgn-field">
<label class="dsgn-label" for="plan">Plan</label>
<input class="dsgn-input" id="plan" value="Team" disabled>
</div>
<div class="dsgn-field">
<label class="dsgn-label" for="vat">VAT number</label>
<input class="dsgn-input" id="vat" value="CZ12345678" readonly>
</div>
</div>Size
An input is exactly as tall as a button in the same density, so a field and a button line up in one row. The border is drawn inside, so it never adds to the height.
Accessibility
- Every control needs a label: a
<label for>or, when there is no room for one, anaria-label. A placeholder is not a label. - Set
autocompleteand the righttypeorinputmode, so phones show the right keyboard and browsers can fill the field. - Link hints and errors with
aria-describedby. Mark an invalid field witharia-invalid="true", not only with colour.
Usage
With icons, the class goes on a wrapper and the control sits inside:
Select is the same wrapper with a chevron:
Date and time: the native control, so the browser's own calendar, keyboard entry and locale format (12. 10. 2026 in Czech) come for free and work on every phone:
Also type="time", "datetime-local" and "month". The picker button sits at the end like a Select chevron (calendar_month / schedule glyph); the picker itself follows light / dark (color-scheme). A range is two date inputs in a Cluster, each with its own label (From / To).
States: :hover, focus (ring), aria-invalid="true", :disabled, [readonly]. Height = line-height + 2 × pad-y, identical to Button, so they line up in a row. The border is an inset box-shadow: it never adds to the height (Figma: stroke inside).
Details
- Classes
.dsgn-input.dsgn-icon.dsgn-field.dsgn-label.dsgn-hint.dsgn-honeypot- Tokens used
--dsgn-border--dsgn-border-control--dsgn-border-width--dsgn-control-font-size--dsgn-control-gap--dsgn-control-height--dsgn-control-line-height--dsgn-control-pad-x--dsgn-control-pad-y--dsgn-danger-solid--dsgn-danger-text--dsgn-duration-fast--dsgn-ease--dsgn-focus--dsgn-focus-danger--dsgn-focus-offset--dsgn-focus-width--dsgn-font-sans--dsgn-font-size-body-s--dsgn-font-size-caption--dsgn-font-weight-medium--dsgn-font-weight-regular--dsgn-line-height-body-s--dsgn-line-height-caption--dsgn-neutral-subtle--dsgn-radius-l--dsgn-radius-m--dsgn-shadow-control--dsgn-space-4--dsgn-surface-base--dsgn-surface-raised--dsgn-text--dsgn-text-disabled--dsgn-text-muted- In Figma
- Input · Textarea · Field · Date input
- Import alone
dsgn.systems/components/input.css