diff options
| author | Danilo M. <danix@danix.xyz> | 2026-04-16 16:55:50 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-04-16 16:55:50 +0200 |
| commit | 691bb79d29429ce9e445753092575ec564c68cd2 (patch) | |
| tree | d48e71e925ab390867e4344a5ab0b700a9924d29 /FORM-COMPONENT-GUIDE.md | |
| parent | a4c5d4fa64f4e5491b1ef3195a00801ea4f21b44 (diff) | |
| download | danixxyz-691bb79d29429ce9e445753092575ec564c68cd2.tar.gz danixxyz-691bb79d29429ce9e445753092575ec564c68cd2.zip | |
feat: add Week 4 documentation (implementation guide, component examples, HANDOFF update)
Diffstat (limited to 'FORM-COMPONENT-GUIDE.md')
| -rw-r--r-- | FORM-COMPONENT-GUIDE.md | 646 |
1 files changed, 646 insertions, 0 deletions
diff --git a/FORM-COMPONENT-GUIDE.md b/FORM-COMPONENT-GUIDE.md new file mode 100644 index 0000000..a916152 --- /dev/null +++ b/FORM-COMPONENT-GUIDE.md @@ -0,0 +1,646 @@ +# Form Component Guide + +Quick reference for all form components with usage examples. + +--- + +## Table of Contents + +1. [Input Fields](#input-fields) +2. [Textareas](#textareas) +3. [Select Dropdowns](#select-dropdowns) +4. [Checkboxes](#checkboxes) +5. [Radio Buttons](#radio-buttons) +6. [Form Groups](#form-groups) +7. [Form Layouts](#form-layouts) +8. [Modals](#modals) +9. [Notifications](#notifications) +10. [Tooltips](#tooltips) + +--- + +## Input Fields + +### Basic Input + +```html +<input type="text" class="form-input" placeholder="Enter text..."> +``` + +### Email Input with Validation + +```html +<div class="form-group"> + <label for="email">Email</label> + <input type="email" id="email" class="form-input" placeholder="user@example.com"> +</div> +``` + +### Password Input + +```html +<div class="form-group"> + <label for="password">Password</label> + <input type="password" id="password" class="form-input" placeholder="••••••"> + <div class="form-group-help">Must be at least 8 characters</div> +</div> +``` + +### Number Input + +```html +<div class="form-group"> + <label for="quantity">Quantity</label> + <input type="number" id="quantity" class="form-input" value="1" min="1"> +</div> +``` + +### Disabled Input + +```html +<input type="text" class="form-input" value="Cannot edit" disabled> +``` + +### Input with Error + +```html +<div class="form-group error"> + <label for="username">Username</label> + <input type="text" id="username" class="form-input error" value="invalid"> + <div class="form-error">Username must be 3-20 characters</div> +</div> +``` + +--- + +## Textareas + +### Basic Textarea + +```html +<textarea class="form-textarea" placeholder="Enter message..."></textarea> +``` + +### Textarea with Label and Help Text + +```html +<div class="form-group"> + <label for="bio">Bio</label> + <textarea id="bio" class="form-textarea" placeholder="Tell us about yourself..."></textarea> + <div class="form-group-help">Maximum 500 characters</div> +</div> +``` + +### Auto-Expanding Textarea + +```html +<div class="form-group"> + <label for="auto-textarea">Auto-expanding Textarea</label> + <textarea + id="auto-textarea" + class="form-textarea auto-expand" + placeholder="Grows as you type..." + @input="autoExpandTextarea($event)"> + </textarea> +</div> +``` + +--- + +## Select Dropdowns + +### Basic Select + +```html +<select class="form-select"> + <option>Choose an option...</option> + <option>Option 1</option> + <option>Option 2</option> + <option>Option 3</option> +</select> +``` + +### Select with Label + +```html +<div class="form-group"> + <label for="country">Country</label> + <select id="country" class="form-select"> + <option>Select a country...</option> + <option value="us">United States</option> + <option value="uk">United Kingdom</option> + <option value="de">Germany</option> + </select> +</div> +``` + +### Multi-Select + +```html +<select class="form-select" multiple> + <option>Python</option> + <option>JavaScript</option> + <option>Go</option> + <option>Rust</option> +</select> +``` + +--- + +## Checkboxes + +### Single Checkbox + +```html +<label class="flex items-center gap-3 cursor-pointer"> + <input type="checkbox" class="form-checkbox"> + <span>I agree to the terms and conditions</span> +</label> +``` + +### Checkbox Group + +```html +<fieldset> + <legend class="font-semibold">Select your interests</legend> + <div class="space-y-2 mt-3"> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="checkbox" class="form-checkbox" name="interests" value="tech"> + <span>Technology</span> + </label> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="checkbox" class="form-checkbox" name="interests" value="design"> + <span>Design</span> + </label> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="checkbox" class="form-checkbox" name="interests" value="business"> + <span>Business</span> + </label> + </div> +</fieldset> +``` + +### Disabled Checkbox + +```html +<label class="flex items-center gap-3 cursor-pointer opacity-50"> + <input type="checkbox" class="form-checkbox" disabled> + <span>This option is not available</span> +</label> +``` + +--- + +## Radio Buttons + +### Radio Button Group + +```html +<fieldset> + <legend class="font-semibold">Choose an option</legend> + <div class="space-y-2 mt-3"> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="radio" name="option" class="form-radio" value="a"> + <span>Option A</span> + </label> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="radio" name="option" class="form-radio" value="b"> + <span>Option B</span> + </label> + <label class="flex items-center gap-3 cursor-pointer"> + <input type="radio" name="option" class="form-radio" value="c"> + <span>Option C</span> + </label> + </div> +</fieldset> +``` + +### Inline Radio Buttons + +```html +<div class="flex gap-6"> + <label class="flex items-center gap-2 cursor-pointer"> + <input type="radio" name="size" class="form-radio" value="sm"> + <span>Small</span> + </label> + <label class="flex items-center gap-2 cursor-pointer"> + <input type="radio" name="size" class="form-radio" value="md"> + <span>Medium</span> + </label> + <label class="flex items-center gap-2 cursor-pointer"> + <input type="radio" name="size" class="form-radio" value="lg"> + <span>Large</span> + </label> +</div> +``` + +--- + +## Form Groups + +### Basic Form Group + +```html +<div class="form-group"> + <label for="name">Name</label> + <input type="text" id="name" class="form-input"> +</div> +``` + +### Required Form Group + +```html +<div class="form-group required"> + <label for="email">Email</label> + <input type="email" id="email" class="form-input" required> +</div> +``` + +### Form Group with Help Text + +```html +<div class="form-group"> + <label for="username">Username</label> + <input type="text" id="username" class="form-input"> + <div class="form-group-help">3-20 characters, alphanumeric only</div> +</div> +``` + +### Form Group with Error + +```html +<div class="form-group error"> + <label for="password">Password</label> + <input type="password" id="password" class="form-input error"> + <div class="form-error">Password must be at least 8 characters</div> +</div> +``` + +--- + +## Form Layouts + +### Single Column Form + +```html +<form class="space-y-4"> + <div class="form-group"> + <label for="name">Name</label> + <input type="text" id="name" class="form-input"> + </div> + + <div class="form-group"> + <label for="email">Email</label> + <input type="email" id="email" class="form-input"> + </div> + + <div class="form-group"> + <label for="message">Message</label> + <textarea id="message" class="form-textarea"></textarea> + </div> + + <button type="submit" class="btn btn-primary">Submit</button> +</form> +``` + +### Two-Column Form (Responsive) + +```html +<form class="space-y-4"> + <div class="form-row"> + <div class="form-group"> + <label for="first">First Name</label> + <input type="text" id="first" class="form-input"> + </div> + <div class="form-group"> + <label for="last">Last Name</label> + <input type="text" id="last" class="form-input"> + </div> + </div> + + <div class="form-row"> + <div class="form-group"> + <label for="phone">Phone</label> + <input type="tel" id="phone" class="form-input"> + </div> + <div class="form-group"> + <label for="country">Country</label> + <select id="country" class="form-select"> + <option>Select...</option> + </select> + </div> + </div> + + <button type="submit" class="btn btn-primary">Submit</button> +</form> +``` + +### Inline Form (Search) + +```html +<div class="form-inline"> + <div class="form-group"> + <label for="search">Search</label> + <input type="search" id="search" class="form-input" placeholder="Type..."> + </div> + <button class="btn btn-primary">Search</button> +</div> +``` + +--- + +## Modals + +### Alert Modal + +```html +<div class="modal" :class="{ active: showAlert }" x-show="showAlert" x-data="{ showAlert: false }"> + <div class="modal-backdrop" @click="showAlert = false"></div> + <div class="modal-content modal-sm"> + <div class="modal-header"> + <h3 class="modal-title">Alert</h3> + <div class="modal-close" @click="showAlert = false"></div> + </div> + <div class="modal-body"> + <p>This is an important message.</p> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" @click="showAlert = false">OK</button> + </div> + </div> +</div> + +<button @click="showAlert = true" class="btn btn-primary">Open Alert</button> +``` + +### Confirm Modal + +```html +<div class="modal" :class="{ active: showConfirm }" x-show="showConfirm" x-data="{ showConfirm: false }"> + <div class="modal-backdrop" @click="showConfirm = false"></div> + <div class="modal-content modal-sm"> + <div class="modal-header"> + <h3 class="modal-title">Confirm Action</h3> + <div class="modal-close" @click="showConfirm = false"></div> + </div> + <div class="modal-body"> + <p>Are you sure you want to delete this item? This action cannot be undone.</p> + </div> + <div class="modal-footer"> + <button class="btn btn-outline" @click="showConfirm = false">Cancel</button> + <button class="btn btn-primary" @click="handleDelete()">Delete</button> + </div> + </div> +</div> +``` + +### Modal with Form + +```html +<div class="modal" :class="{ active: showModal }" x-show="showModal" x-data="{ showModal: false, form: {} }"> + <div class="modal-backdrop" @click="showModal = false"></div> + <div class="modal-content modal-md"> + <div class="modal-header"> + <h3 class="modal-title">Edit Profile</h3> + <div class="modal-close" @click="showModal = false"></div> + </div> + <form @submit.prevent="saveProfile()"> + <div class="modal-body space-y-4"> + <div class="form-group"> + <label for="name">Name</label> + <input type="text" id="name" class="form-input" x-model="form.name"> + </div> + <div class="form-group"> + <label for="bio">Bio</label> + <textarea id="bio" class="form-textarea" x-model="form.bio"></textarea> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-outline" @click="showModal = false">Cancel</button> + <button type="submit" class="btn btn-primary">Save</button> + </div> + </form> + </div> +</div> +``` + +--- + +## Notifications + +### Toast Notification + +```html +<!-- Container in layout --> +<div class="toast-container" x-data="formComponentsData()"> + <template x-for="toast in toasts" :key="toast.id"> + <div class="toast" :class="`toast-${toast.type}`"> + <span x-text="toast.message"></span> + <div class="toast-close" @click="removeToast(toast.id)"></div> + </div> + </template> +</div> + +<!-- Trigger toast --> +<button @click="showToast('success', 'Item saved!')">Save</button> +<button @click="showToast('error', 'Failed to delete.')">Delete</button> +<button @click="showToast('info', 'Welcome back!')">Info</button> +<button @click="showToast('warning', 'Unsaved changes.')">Warning</button> +``` + +### Toast Usage in Forms + +```html +<form @submit.prevent="submitForm()"> + <!-- Form fields --> + <button type="submit" class="btn btn-primary" :disabled="isSubmitting"> + {{ isSubmitting ? 'Submitting...' : 'Submit' }} + </button> +</form> + +<script> +function formData() { + return { + isSubmitting: false, + async submitForm() { + this.isSubmitting = true; + try { + await fetch('/api/submit', { method: 'POST' }); + this.showToast('success', 'Form submitted successfully!'); + } catch (error) { + this.showToast('error', 'Failed to submit form.'); + } finally { + this.isSubmitting = false; + } + } + }; +} +</script> +``` + +--- + +## Tooltips + +### Top Tooltip (Default) + +```html +<div class="tooltip"> + <span>Hover me</span> + <span class="tooltip-text">I'm a tooltip on top!</span> +</div> +``` + +### Bottom Tooltip + +```html +<div class="tooltip tooltip-bottom"> + <span>Hover me</span> + <span class="tooltip-text">I'm below!</span> +</div> +``` + +### Left Tooltip + +```html +<div class="tooltip tooltip-left"> + <span>Hover me</span> + <span class="tooltip-text">I'm on the left!</span> +</div> +``` + +### Right Tooltip + +```html +<div class="tooltip tooltip-right"> + <span>Hover me</span> + <span class="tooltip-text">I'm on the right!</span> +</div> +``` + +### Tooltip with Icon + +```html +<div class="tooltip" title="Click to copy email"> + <button class="btn btn-icon"> + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> + <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path> + </svg> + </button> + <span class="tooltip-text">Copy to clipboard</span> +</div> +``` + +--- + +## Loading States + +### Button with Spinner + +```html +<button class="btn btn-primary" :disabled="isLoading"> + <span x-show="isLoading" class="spinner mr-2"></span> + {{ isLoading ? 'Submitting...' : 'Submit' }} +</button> +``` + +### Spinner Sizes + +```html +<div class="spinner spinner-sm"></div> +<div class="spinner"></div> +<div class="spinner spinner-lg"></div> +``` + +--- + +## Complete Contact Form Example + +```html +<form x-data="formComponentsData()" @submit.prevent="submitForm()" class="space-y-4 max-w-md"> + <div class="form-group required"> + <label for="name">Name</label> + <input + type="text" + id="name" + class="form-input" + x-model="form.name" + @blur="validateName()" + :class="{ error: errors.name }" + required> + <div x-show="errors.name" class="form-error" x-text="errors.name"></div> + </div> + + <div class="form-group required"> + <label for="email">Email</label> + <input + type="email" + id="email" + class="form-input" + x-model="form.email" + @blur="validateEmail()" + :class="{ error: errors.email }" + required> + <div x-show="errors.email" class="form-error" x-text="errors.email"></div> + </div> + + <div class="form-group required"> + <label for="message">Message</label> + <textarea + id="message" + class="form-textarea auto-expand" + x-model="form.message" + @input="autoExpandTextarea($event)" + required + placeholder="Your message..."></textarea> + </div> + + <div class="form-group"> + <label class="flex items-center gap-3"> + <input type="checkbox" class="form-checkbox" x-model="form.subscribe"> + <span>Subscribe to our newsletter</span> + </label> + </div> + + <button + type="submit" + class="btn btn-primary w-full" + :disabled="isSubmitting"> + <span x-show="isSubmitting" class="spinner mr-2"></span> + {{ isSubmitting ? 'Submitting...' : 'Send Message' }} + </button> +</form> +``` + +--- + +## Keyboard Shortcuts + +| Key | Action | +|-----|--------| +| Tab | Focus next form field | +| Shift+Tab | Focus previous form field | +| Space | Toggle checkbox/radio | +| Enter | Submit form / Confirm dialog | +| Escape | Close modal / Cancel dialog | +| Arrow Up/Down | Navigate select options | + +--- + +## Best Practices + +1. **Always use labels** — Associate with `for` attribute +2. **Group related fields** — Use `.form-group` wrapper +3. **Provide help text** — Use `.form-group-help` for guidance +4. **Show errors clearly** — Use `.form-error` with specific messages +5. **Test keyboard navigation** — Use Tab, Shift+Tab, Enter, Space, Escape +6. **Verify contrast** — Check both dark and light modes +7. **Respect motion preferences** — Use `prefers-reduced-motion` media query +8. **Validate early** — Real-time feedback, but allow recovery +9. **Disable during submission** — Prevent duplicate submissions +10. **Use semantic HTML** — `<fieldset>`, `<legend>`, `<label>` elements + +--- + +**Last Updated:** 2026-04-16 +**Version:** 1.0 |
