Components
Form
A form orchestrator that handles synchronous validation, focus management, and alert state.
Preview
Usage
<st-form>
<form action="/login" method="POST">
<st-field class="grid gap-2">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
</st-field>
<st-field class="grid gap-2">
<label for="password">Password</label>
<input id="password" name="password" type="password" required>
</st-field>
<button type="submit">Sign in</button>
</form>
</st-form>
Handling Server Errors
For fetch-based submissions, use setServerErrors() to display Laravel's 422 validation errors:
const stForm = document.querySelector('st-form')
const form = stForm.querySelector('form')
form.addEventListener('submit', async (e) => {
e.preventDefault()
const res = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
headers: { 'Accept': 'application/json' }
})
if (res.status === 422) {
const { errors } = await res.json()
stForm.setServerErrors(errors)
} else if (res.ok) {
window.location = '/dashboard'
}
})
Laravel Blade Integration
<st-field> works with Laravel's @error directive out of the box. Server-rendered errors are the source of truth on initial load; client-side validation takes over when the user interacts:
<st-field class="grid gap-2">
<label for="email">Email address</label>
<input
id="email"
name="email"
type="email"
required
value="{{ old('email') }}"
@error('email') aria-invalid="true" @enderror
>
@error('email')
<p data-error class="text-sm text-destructive">{{ $message }}</p>
@enderror
</st-field>
How It Works
st-field discovers existing <p data-error> elements and aria-invalid attributes on page load.
If server errors exist, the field is treated as "touched" — client-side validation updates errors in place.
If no server error exists, the error element is created dynamically when validation fails.
No-JavaScript Fallback
This pattern works without JavaScript: the form renders, errors display, the user can submit. JavaScript adds client-side validation and dynamic error updates on top.