Skip to content

Form field

wu-field stacks a label, a control and its messages. The required marker and the error message follow the control’s own state, with no script.

Class, attribute or variable Effect
wu-field Root. Column of label, control and messages
wu-field-label Part, on <label>. Medium weight label
required or aria-required="true" on the control Adds a * after the label, kept out of the label’s accessible name
wu-field-message error inside the field Hidden until the control has aria-invalid="true" or matches :user-invalid. Reference its id from aria-describedby only while it shows
horizontal Label beside the control from sm up
floating Label inside the input, moved up on focus or once filled
animated The floating label slides, opt-in
--wu-field--LabelWidth Label column width in horizontal

As it appears on your ID.

<div class="wu-field">
<label class="wu-field-label" for="field-name">Full name</label>
<input class="wu-input" id="field-name" type="text" aria-describedby="field-name-hint">
<p class="wu-field-message" id="field-name-hint">As it appears on your ID.</p>
</div>

The error message shows once the control is invalid: after the user has interacted (:user-invalid), or right away with aria-invalid="true".

A screen reader reads everything aria-describedby points to, hidden or not. So the error’s id joins aria-describedby only while the error shows:

  • Invalid when the page is rendered (server validation): set aria-invalid="true" and add the error id to aria-describedby, as in the invite code field.
  • Invalid after the user acts (:user-invalid): leave the error id out, as in the email field. The error shows for sighted users and the browser announces its own validation message on submit. To announce your own text instead, have your script set aria-invalid="true" and add the id when the field turns invalid.

Error: enter an email address.

Error: the code has 8 characters.

<div class="flex col gap-4">
<div class="wu-field">
<label class="wu-field-label" for="field-email">Email</label>
<input class="wu-input" id="field-email" type="email" required>
<p class="wu-field-message error" id="field-email-error">Error: enter an email address.</p>
</div>
<div class="wu-field">
<label class="wu-field-label" for="field-code">Invite code</label>
<input class="wu-input" id="field-code" type="text" value="ABC" aria-invalid="true" aria-describedby="field-code-error">
<p class="wu-field-message error" id="field-code-error">Error: the code has 8 characters.</p>
</div>
</div>

Set --wu-field--LabelWidth on a shared parent, so the controls of every field line up in one column.

Used for tax.

<div class="flex col gap-4" style="--wu-field--LabelWidth: 6rem">
<div class="wu-field horizontal">
<label class="wu-field-label" for="field-company">Company</label>
<input class="wu-input" id="field-company" type="text">
</div>
<div class="wu-field horizontal">
<label class="wu-field-label" for="field-city">City</label>
<input class="wu-input" id="field-city" type="text" aria-describedby="field-city-hint">
<p class="wu-field-message" id="field-city-hint">Used for tax.</p>
</div>
</div>

Needs placeholder=" " on the input, so the label knows when it is filled. Not combined with horizontal.

<div class="wu-field floating animated">
<label class="wu-field-label" for="field-search">Search projects</label>
<input class="wu-input" id="field-search" type="search" placeholder=" ">
</div>

The label, the required marker and the horizontal layout follow the inline direction.

تلميح: لا نشاركه أبدًا.

<div class="wu-field horizontal">
<label class="wu-field-label" for="field-rtl">البريد الإلكتروني</label>
<input class="wu-input" id="field-rtl" type="email" required>
<p class="wu-field-message">تلميح: لا نشاركه أبدًا.</p>
</div>
@use "@wovenui/components/field";

The field needs no other component. The examples above also use the input and the field message.