[ @sdxc/u/state ]
invalid
Waits for user interaction before flagging a field invalid, matching :user-invalid alongside the ARIA fallback so validation only surfaces once it is meaningful to the person filling in the field.
import { invalid } from "@sdxc/u/state";Quick reference
Every documented call, beside the CSS it emits.
| Call | CSS |
|---|---|
u.invalid(u.border("danger")) | css({ '&:user-invalid, &[aria-invalid="true"]': { borderColor: "..." } }) |
Examples
Basic example
Wrap utilities in invalid() to style a field that fails validation after the user has edited it. Type "hello" in the field, then click outside it:
<label mix={[vstack({ gap: 1 }), text("sm"), weight("medium")]}>
Email
<input
type="email"
required
placeholder="you@example.com"
mix={[
border("neutral.border"),
invalid([border("danger.strong"), fg("danger"), outline({ color: "danger", width: 1 })]),
...,
]}
/>
</label>ARIA invalid
invalid() also matches aria-invalid="true", for a field the server rejected:
<label mix={[vstack({ gap: 1 }), text("sm"), weight("medium")]}>
Username
<input
type="text"
value="admin"
aria-invalid="true"
aria-describedby="username-error"
mix={[
border("neutral.border"),
invalid([border("danger.strong"), fg("danger")]),
...,
]}
/>
<span id="username-error" mix={[fg("danger"), text("xs")]}>
That username is taken.
</span>
</label>Responsive design
Wrap the call in a container query to scope it to one width.
u.at("md", u.invalid(u.border("danger")))Signature
u.invalid(input: UtilityInput<Node>)