Build type-safe HTML input elements with validation and state management.
This module uses phantom types to ensure inputs are properly configured before
being rendered. An input must have interaction (via withOnChange or withDisabled)
before it can be built into HTML.
Phantom type representing an input without interaction.
Inputs with this type cannot be built yet - they need to be given interaction
via withOnChange or withDisabled.
Phantom type representing an input with interaction.
Inputs with this type can be built into HTML.
Create a new input with a label.
The input starts as Dumb, meaning it cannot be built yet. You must add
interaction via withOnChange or withDisabled before building.
new "Email Address"
new "Password"
|> withType "password"
|> withRequired True
|> withOnChange PasswordChangedMark an input as required or optional.
This sets the HTML required attribute.
new "Email"
|> withRequired TrueSet the input type (e.g., "text", "email", "password", "number").
new "Password"
|> withType "password"
|> withRequired True
|> withOnChange PasswordChangedAdd placeholder text to an input.
new "Search"
|> withPlaceholder "Type to search..."
|> withOnChange SearchChangedAdd a transformer function that processes the input value.
The transformer is applied to the value before it's passed to the onChange handler.
This is useful for formatting, trimming, or normalizing input.
new "Username"
|> withTransformer String.trim
|> withOnChange UsernameChanged
new "Code"
|> withTransformer String.toUpper
|> withOnChange CodeChangedAdd a validator function that returns additional HTML attributes on validation failure.
The validator receives the current value and can return error attributes that will be applied to the input element. This is useful for providing visual feedback or ARIA attributes for accessibility.
import Html.Attributes as Attr
lengthValidator : String -> Result (List (Html.Attribute msg)) ()
lengthValidator value =
if String.length value >= 3 then
Ok ()
else
Err
[ Attr.class "invalid"
, Attr.attribute "aria-invalid" "true"
]
new "Username"
|> withValidator lengthValidator
|> withOnChange UsernameChangedAdd custom HTML attributes to an input.
import Html.Attributes as Attr
new "Email"
|> withAttributes
[ Attr.class "form-input"
, Attr.autocomplete False
]
|> withOnChange EmailChangedAdd an onChange handler to make the input interactive.
This is required before an input can be built. The handler receives the transformed value after any transformer has been applied.
type Msg
= NameChanged String
new "Name"
|> withTransformer String.trim
|> withOnChange NameChanged
|> build currentValueConvert a Dumb input to a disabled input with interaction.
This allows you to build a disabled input without providing an onChange handler.
new "Disabled Field"
|> withDisabled
|> build ""Build an input into HTML.
The input must have interaction (via withOnChange or withDisabled) to be buildable.
The build function is optimized with lazy rendering for performance.
type Msg
= EmailChanged String
view : String -> Html Msg
view emailValue =
new "Email"
|> withType "email"
|> withRequired True
|> withOnChange EmailChanged
|> build emailValue
An input element with a phantom type parameter for compile-time state tracking.
The phantom type ensures that inputs have proper interaction handlers before they can be rendered.