libra/docs/stories/story-9.5-component-styling...

7.9 KiB

Story 9.5: Component Styling - Forms

Epic Reference

Epic 9: Design & Branding Implementation

User Story

As a user, I want consistent, accessible form styling, So that data entry is intuitive and error states are clear.

Dependencies

  • Story 9.1 (Color System) - Must be completed first; provides Tailwind color aliases used below
  • Story 9.2 (Typography System) - Font weights for labels

Color Reference (from Story 9.1)

For quick reference, this story uses these colors defined in the Tailwind theme:

  • gold (#D4AF37) - Focus states, checkbox accents
  • charcoal (#2C3E50) - Default borders, label text
  • danger (#E74C3C) - Error states
  • cream (#F9F7F4) - Input backgrounds (if needed)

Acceptance Criteria

Input Fields

  • Border: Charcoal Gray (border-charcoal/30)
  • Focus: Gold border with subtle ring (focus:border-gold focus:ring-gold/20)
  • Border-radius: 6px (rounded-md)
  • Padding: 12px 16px (px-4 py-3)

Textareas

  • Same styling as inputs
  • Minimum height: 120px (min-h-[120px])

Select Dropdowns

  • Custom styled using Flux UI (not native browser)
  • Consistent border/focus styling with inputs

Checkboxes & Radios

  • Custom styled with gold accent when checked
  • Clear visual distinction between checked/unchecked states

Labels

  • SemiBold weight (font-semibold)
  • Required indicator (*) in danger color

Error States

  • Red border (border-danger)
  • Error message displayed below field
  • Error ring on focus (focus:ring-danger/20)

RTL Support

  • Labels align to the right in RTL mode
  • Input text direction follows locale
  • Error messages align correctly
  • Padding swaps appropriately (use ps-4 pe-4 instead of px-4 if needed)

Files to Create/Modify

Primary Files

  • resources/css/app.css - Add form component utility classes

Flux UI Integration

Flux UI Free includes these form components that need styling customization:

  • flux:input - Text inputs
  • flux:textarea - Multiline text
  • flux:select - Dropdown selects
  • flux:checkbox - Checkboxes
  • flux:radio - Radio buttons
  • flux:field - Field wrapper with label/error support

Existing Forms to Audit

Review and update existing forms in:

  • resources/views/livewire/ - Any Volt components with forms
  • Authentication views (login, register, password reset)
  • Contact/booking forms

Technical Implementation

CSS Classes (add to resources/css/app.css)

/* Form field styling */
.input-field {
  @apply w-full border border-charcoal/30 rounded-md px-4 py-3
         focus:border-gold focus:ring-2 focus:ring-gold/20
         transition-colors outline-none bg-white;
}

.input-error {
  @apply border-danger focus:border-danger focus:ring-danger/20;
}

.form-label {
  @apply block text-sm font-semibold text-charcoal mb-2;
}

.form-label-required::after {
  content: ' *';
  @apply text-danger;
}

.error-message {
  @apply text-sm text-danger mt-1;
}

/* Textarea specific */
.textarea-field {
  @apply input-field min-h-[120px] resize-y;
}

/* Custom checkbox */
.checkbox-custom {
  @apply w-5 h-5 rounded border-charcoal/30 text-gold
         focus:ring-gold focus:ring-offset-0;
}

/* Custom radio */
.radio-custom {
  @apply w-5 h-5 border-charcoal/30 text-gold
         focus:ring-gold focus:ring-offset-0;
}

Flux UI Component Usage Examples

{{-- Basic input with label --}}
<flux:field>
    <flux:label class="form-label">Email</flux:label>
    <flux:input type="email" wire:model="email" class="input-field" />
</flux:field>

{{-- Required field with error --}}
<flux:field>
    <flux:label class="form-label form-label-required">Name</flux:label>
    <flux:input
        wire:model="name"
        class="input-field @error('name') input-error @enderror"
    />
    @error('name')
        <span class="error-message">{{ $message }}</span>
    @enderror
</flux:field>

{{-- Textarea --}}
<flux:field>
    <flux:label class="form-label">Message</flux:label>
    <flux:textarea wire:model="message" class="textarea-field" />
</flux:field>

{{-- Select dropdown --}}
<flux:field>
    <flux:label class="form-label">Category</flux:label>
    <flux:select wire:model="category" class="input-field">
        <flux:select.option value="">Select...</flux:select.option>
        <flux:select.option value="legal">Legal</flux:select.option>
        <flux:select.option value="general">General</flux:select.option>
    </flux:select>
</flux:field>

{{-- Checkbox with gold accent --}}
<flux:field>
    <flux:checkbox wire:model="agree" class="checkbox-custom" />
    <flux:label class="form-label inline ms-2">I agree to the terms</flux:label>
</flux:field>

{{-- Radio group --}}
<flux:field>
    <flux:label class="form-label form-label-required">Preferred Contact</flux:label>
    <div class="flex gap-4 mt-2">
        <label class="flex items-center gap-2">
            <flux:radio wire:model="contact" value="email" class="radio-custom" />
            <span>Email</span>
        </label>
        <label class="flex items-center gap-2">
            <flux:radio wire:model="contact" value="phone" class="radio-custom" />
            <span>Phone</span>
        </label>
    </div>
</flux:field>

RTL Considerations

  • Use logical properties where possible (ps-, pe-, ms-, me- instead of pl-, pr-, ml-, mr-)
  • Flux components should handle RTL automatically with dir="rtl" on the HTML element
  • Test label positioning in Arabic locale

Testing Requirements

Manual Testing Checklist

  1. Visual Inspection (both locales)

    • Switch to Arabic - verify RTL alignment
    • Switch to English - verify LTR alignment
    • All form elements match design specs
  2. Interactive States

    • Click into each field type - verify gold focus ring appears
    • Tab through form - verify focus order is logical
    • Submit with errors - verify error styling appears
  3. Accessibility

    • Labels are associated with inputs (clicking label focuses input)
    • Error messages are announced to screen readers
    • Focus indicators are clearly visible

Automated Tests

Create feature test for form styling verification:

// tests/Feature/FormStylingTest.php
test('form fields render with correct classes', function () {
    // Test that forms include the expected CSS classes
    $this->get('/contact')
        ->assertSee('input-field')
        ->assertSee('form-label');
});

test('form error states display correctly', function () {
    // Submit form with invalid data and check error styling
    Livewire::test('contact-form')
        ->set('email', 'invalid')
        ->call('submit')
        ->assertSee('input-error')
        ->assertSee('error-message');
});

Browser Testing (RTL Verification)

// tests/Browser/FormRtlTest.php
it('displays form labels on the right in RTL mode', function () {
    visit('/ar/contact')
        ->assertPresent('[dir="rtl"]')
        ->assertVisible('.form-label');
    // Visual inspection for alignment
});

Definition of Done

  • CSS classes added to resources/css/app.css
  • Input styling matches specs (border, focus, padding, radius)
  • Textarea styling consistent with inputs, min-height 120px
  • Select dropdowns styled consistently (not native)
  • Checkboxes show gold accent when checked
  • Radio buttons show gold accent when selected
  • Labels are semibold with required indicator working
  • Error states show red border and message below
  • RTL alignment verified in Arabic locale
  • LTR alignment verified in English locale
  • Existing forms updated to use new classes
  • Feature tests pass
  • Code formatted with Pint

Estimation

Complexity: Medium | Effort: 3-4 hours

Dev Notes

  • Check Flux UI docs for any built-in theming options before adding custom CSS
  • If Flux components don't accept className props well, may need to use CSS selectors targeting Flux's rendered HTML
  • Run npm run build after CSS changes to see updates