Forms
Build accessible, user-friendly forms with our comprehensive set of form components. Each component follows consistent patterns, uses typography tokens for visual hierarchy, and includes built-in accessibility features.
Available Components
Input Fields
- TextInput - Text entry for various data types (text, email, password, etc.)
- Textarea - Multi-line text input for longer content with auto-resize
- Select - Dropdown selection from predefined options
Selection Controls
- Checkbox - Multiple selection from a group of options
- RadioGroup - Single selection from mutually exclusive options
- Toggle - Binary on/off switches for immediate settings
Design Principles
1. Consistent Typography
All form components use the design system’s typography tokens to maintain visual hierarchy:
/* Labels */
--typography-caption-size
--typography-caption-color
--typography-caption-weight
/* Input text */
--typography-body-size
--typography-body-color
--typography-body-weight
/* Helper/Error text */
--typography-caption-size
--typography-muted-color /* helper */
--error /* error state */ 2. Clear Visual States
Every form component supports these states:
- Default - Normal interactive state
- Focus - Clear focus ring for keyboard navigation
- Disabled - Reduced opacity and no interaction
- Error - Red border with error message
- Required - Asterisk indicator on label
3. Accessibility First
All components include:
- Proper ARIA attributes (
aria-required,aria-invalid,aria-describedby) - Keyboard navigation support
- Screen reader announcements
- Proper label associations
- Focus management
Form Patterns
Basic Form Structure
<script>
import TextInput from '$lib/shared/components/forms/TextInput.svelte';
import Checkbox from '$lib/shared/components/forms/Checkbox.svelte';
import Button from '$lib/shared/components/primitives/Button.svelte';
let formData = $state({
name: '',
email: '',
agree: false
});
let errors = $state({});
function handleSubmit(e) {
e.preventDefault();
// Validation logic
if (!formData.name) {
errors.name = 'Name is required';
return;
}
// Submit logic
}
</script>
<form on:submit={handleSubmit}>
<TextInput
id="name"
label="Full Name"
bind:value={formData.name}
error={errors.name}
required
/>
<TextInput
id="email"
type="email"
label="Email Address"
bind:value={formData.email}
error={errors.email}
required
/>
<Checkbox
id="agree"
label="I agree to the terms"
bind:checked={formData.agree}
error={errors.agree}
required
/>
<Button type="submit">Submit</Button>
</form> Validation Strategies
1. On Submit Validation
Validate all fields when the form is submitted:
function validateForm(data) {
const errors = {};
if (!data.email) {
errors.email = 'Email is required';
} else if (!data.email.includes('@')) {
errors.email = 'Invalid email format';
}
return errors;
} 2. On Blur Validation
Validate individual fields when they lose focus:
<TextInput
id="email"
type="email"
label="Email"
bind:value={email}
error={emailError}
onblur={() => {
if (!email.includes('@')) {
emailError = 'Invalid email';
}
}}
/> 3. Real-time Validation
Validate as the user types (use sparingly):
$effect(() => {
if (password.length > 0 && password.length < 8) {
passwordError = 'Password must be at least 8 characters';
} else {
passwordError = null;
}
}); Form Layout
Vertical Stacking
Default pattern for most forms:
.form-stack {
display: flex;
flex-direction: column;
gap: var(--space-4);
max-width: 480px;
} Grid Layout
For complex forms with multiple columns:
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--space-6);
} Grouped Sections
Use fieldsets to group related fields:
<fieldset>
<legend>Contact Information</legend>
<TextInput id="email" label="Email" />
<TextInput id="phone" label="Phone" />
</fieldset> Error Handling
Error Message Guidelines
- Be specific - “Enter a valid email address” not “Invalid input”
- Be helpful - Explain what’s needed to fix the error
- Be timely - Show errors at the right moment
- Be visible - Use color and icons for clarity
Error Display Pattern
{#if error}
<div role="alert" aria-live="polite" class="field-error-message">
<Icon src="/svg/error.svg" size={16} />
<span>{error}</span>
</div>
{/if} Accessibility Checklist
Labels
- ✓ Every input has a label
- ✓ Labels are associated via
for/id - ✓ Required fields marked with asterisk
- ✓ Helper text linked via
aria-describedby
Keyboard Navigation
- ✓ All inputs reachable via Tab
- ✓ Focus indicators visible
- ✓ Enter submits forms
- ✓ Escape cancels modals
Screen Readers
- ✓ Error messages announced
- ✓ Required fields identified
- ✓ Field purposes clear
- ✓ Form submission feedback
Visual Design
- ✓ Color not sole indicator
- ✓ Sufficient contrast ratios
- ✓ Touch targets ≥44×44px
- ✓ Clear visual hierarchy
Best Practices
1. Progressive Disclosure
Show only necessary fields initially:
- Use conditional fields based on previous answers
- Group advanced options in collapsible sections
- Implement multi-step forms for complex processes
2. Smart Defaults
Reduce user effort:
- Pre-fill known information
- Use sensible default values
- Remember user preferences
- Auto-format inputs (phone, date, etc.)
3. Clear Actions
Make form intentions obvious:
- Use descriptive button labels (“Create Account” not “Submit”)
- Differentiate primary and secondary actions
- Provide clear cancel/reset options
- Show loading states during submission
4. Mobile Optimization
Ensure forms work on all devices:
- Use appropriate input types (
type="email",type="tel") - Ensure touch targets are large enough
- Test with virtual keyboards
- Consider landscape orientation
Form Examples
Login Form
Simple authentication with email and password
Registration Form
Multi-step user registration with validation
Settings Form
Preferences with toggles and checkboxes
Contact Form
Message submission with file upload
Search Form
Filters with various input types
Performance Tips
- Debounce validations - Don’t validate on every keystroke
- Lazy load components - Load complex inputs only when needed
- Optimize re-renders - Use
$stateand$derivedefficiently - Cache form data - Preserve user input on navigation
- Batch updates - Group multiple field changes
Related Resources
- Typography System - Text styling tokens
- Color System - Semantic colors for states
- Spacing System - Consistent form spacing
- Error Handling - Form validation and errors