Input
Displays a form input field.
src/components/rahti_ui/input.rs
Installation
Install this component in your Rahti 0.0.58 application. Class conflicts are resolved with the existing frontend `twMerge`; no Rust class-merging dependency is needed.
Types
`type` is an ordinary attribute, and left unset an `<input>` is a text field — which is why the first one writes no `type` at all. `.email()`, `.password()`, `.search()`, `.number()`, `.tel()`, `.url()` and `.file()` are shorthands for `.kind(…)`.
States
A `false` leaves the attribute off rather than writing `disabled="false"`, which HTML would read as disabled. `.invalid(true)` writes `aria-invalid`, and the `aria-invalid:` utilities in the class list do the rest.
With a label
`id` and `name` are named props for the same reason `placeholder` is: they are what a form is actually written with. Everything rarer goes through `attrs`.
We will not send anything anywhere.
Attributes
`.attr(…)` writes anything; `.unset(…)` takes one away, which is the thing a value cannot express and the reason a forwarded set is an `Attrs` rather than a list of pairs. The last field has no `data-slot`.
Class override
Rust composes the component and caller class lists. When utilities conflict, use the existing frontend `twMerge` in a compiled class binding.
Controlled, page scope
A field whose value is this page's state belongs on markup this page owns. `input_variants` returns the same class list the component renders, so a native `<input>` here is an Input in every way that shows. `value={…}` is a controlled binding; PulsePoint keeps it and the state in step.
You typed {query.length} character(s): {query || "—"}
Validation, inline
`.render()` returns the element itself, with no boundary around it, so interpolating it into this block puts it in this block's scope. Handlers and bindings both work, and it is still the same component. `aria-invalid` is bound here, which is what paints the field — the accessible state and the styling are one fact.
{email === "" ? "Waiting for an address." : email.includes("@") ? "Looks like an address." : "Missing an @ — the field is marked invalid."}
The component tag, and its boundary
The tag is the right call for a field this page does not drive — a type, a name, a placeholder, a `required`. What a plain form posts, the tag renders.
Through the tag
A form control's state crosses the boundary the way a click does. A component's root attributes are evaluated where the tag was written, so `value` and `oninput` read and write this page's state.
The other two spellings are the first two sections — `.render()` interpolated into this block, or `input_variants` on a native `<input>` — for a field assembled in Rust or an element this component does not render.