Files
thrillwiki_laravel/memory-bank/design/MenuComponents.md

3.4 KiB

Menu Components

Menu Behavior (Auth, User, and Mobile)

All menu components implement consistent behavior for opening and closing using pure Livewire functionality:

  1. Click Outside to Close

    • Uses wire:click.away="close" to close menu when clicking outside
    • Calls the Livewire close() method directly
  2. Toggle on Button Click

    • Uses wire:click.stop="toggle" on the trigger button/image
    • Prevents event bubbling with wire:click.stop
    • Toggle method directly flips the boolean state
    • Simple and efficient state management
  3. Menu Styling and Behavior

    • Uses z-index to ensure proper stacking
    • Full-width menu items for better clickability
    • Consistent hover and focus states
    • Left-aligned text in buttons for consistency
  4. Accessibility Features

    • Proper ARIA roles and attributes
    • Focus management for keyboard navigation
    • Clear visual feedback on focus
    • Semantic HTML structure

Mobile Menu Specific Features

  1. Backdrop Handling

    • Semi-transparent backdrop when menu is open
    • Clicking backdrop closes menu
    • Smooth opacity transitions
  2. Responsive Behavior

    • Hidden on larger screens (lg:hidden)
    • Full-width menu on mobile
    • Smooth slide and fade transitions
  3. Navigation Links

    • Full-width clickable areas
    • Consistent spacing and padding
    • Clear visual feedback on hover/focus
    • Proper role attributes

Implementation Details

All components share identical state management and methods:

class MenuComponent extends Component
{
    public bool $isOpen = false;

    public function toggle()
    {
        $this->isOpen = !$this->isOpen;
    }

    public function close()
    {
        $this->isOpen = false;
    }
}

Menu buttons include proper accessibility attributes:

<button
    wire:click.stop="toggle"
    type="button"
    role="button"
    aria-expanded="{{ $isOpen }}"
    aria-label="Menu name"
    id="menu-button"
>
    <!-- Button content -->
</button>

Menu containers have proper ARIA roles:

<div
    wire:key="menu-name"
    wire:click.away="close"
    role="menu"
    aria-orientation="vertical"
    aria-labelledby="menu-button"
    class="... {{ $isOpen ? 'visible-state' : 'hidden-state' }}"
>

Menu items have consistent styling and accessibility:

<a 
    href="{{ route('item.route') }}" 
    role="menuitem"
    class="flex items-center w-full gap-3 px-4 py-3 text-gray-300 transition-colors hover:text-white hover:bg-gray-800/50 focus:outline-none focus:text-white focus:bg-gray-800/50"
>
    <i class="w-5 fas fa-icon"></i>
    <span>Menu Item</span>
</a>

Mobile menu backdrop:

<div
    class="fixed inset-0 bg-black/50 transition-opacity duration-300 lg:hidden {{ $isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none' }}"
    wire:click="close"
></div>

This implementation:

  • Uses pure Livewire without Alpine.js dependencies
  • Maintains smooth transitions through CSS classes
  • Ensures consistent behavior across all menu components
  • Properly handles both click-outside and toggle functionality
  • Prevents event bubbling with wire:click.stop
  • Ensures proper re-rendering with wire:key
  • Uses simplified toggle logic for better reliability
  • Provides consistent styling and behavior for all menu items
  • Implements proper accessibility features throughout
  • Supports both mouse and keyboard interactions
  • Handles mobile-specific requirements elegantly