Day 7 - Component Challenge

Challenge UI with Livewire & Alpine.js

Day 7

Day 7

Pagination & Breadcrumbs

Pagination

Composant de pagination personnalisé avec intégration Livewire complète pour la navigation des données.

Features:

  • Livewire integration
  • Smart ellipsis logic
  • Previous/Next buttons
  • Disabled states
  • Results counter
  • ARIA accessible

Villes du Cameroun

Ville Région Population
Yaoundé Centre 4 million
Douala Littoral 3.5 million
Bafoussam Ouest 500k
Garoua Nord 600k
Bamenda Nord-Ouest 500k
Showing 1 to 5 of 15 results

Breadcrumbs

Fil d'Ariane pour afficher la hiérarchie de navigation et améliorer l'expérience utilisateur.

Features:

  • Icon separators
  • Active page indication
  • Flexible item format
  • ARIA accessible
  • Hover effects

Basic Navigation

Administrative Navigation (Cameroon)

Slash Separator

Dot Separator

Combined Usage Example

Liste des Étudiants - Université de Yaoundé I

Exemple d'intégration pagination et breadcrumbs

Contenu paginé avec breadcrumb de navigation

Showing 1 to 5 of 15 results

Usage Examples

Pagination Usage

<?php
 
use Livewire\Component;
use Livewire\WithPagination;
 
new class extends Component {
use WithPagination;
 
public function render()
{
return view('livewire.users', [
'users' => User::paginate(10),
]);
}
};

2. In Your Blade View

<div>
{{-- Your content --}}
@foreach($users as $user)
<div>{{ $user->name }}</div>
@endforeach
 
{{-- Pagination --}}
<x-ui.pagination :paginator="$users" />
</div>

Advanced Usage

Custom Per Page

public int $perPage = 15;
 
public function render()
{
return view('livewire.products', [
'products' => Product::paginate($this->perPage),
]);
}

With Filtering

use Livewire\WithPagination;
 
public string $search = '';
 
public function updatingSearch()
{
$this->resetPage(); // Reset to page 1 when search changes
}
 
public function render()
{
return view('livewire.items', [
'items' => Item::query()
->when($this->search, fn($query) =>
$query->where('name', 'like', '%' . $this->search . '%')
)
->paginate(10),
]);
}

Using LengthAwarePaginator

use Illuminate\Pagination\LengthAwarePaginator;
 
public function getDataProperty()
{
$allItems = collect([/* */]);
$perPage = 10;
$currentPage = $this->getPage();
 
$items = $allItems->forPage($currentPage, $perPage);
 
return new LengthAwarePaginator(
$items,
$allItems->count(),
$perPage,
$currentPage,
['path' => request()->url()]
);
}

Pagination Logic

The component automatically handles:

  • 7 or fewer pages: Shows all page numbers
  • Current page near start: [1, 2, 3, 4, ..., Last]
  • Current page near end: [1, ..., N-3, N-2, N-1, N]
  • Current page in middle: [1, ..., N-1, N, N+1, ..., Last]

Props

Prop Type Required Description
paginator LengthAwarePaginator Yes Laravel paginator instance

Styling

The component uses Tailwind CSS with these key classes:

  • border-border: Border colors
  • bg-primary: Active page background
  • text-primary-foreground: Active page text
  • hover:bg-accent: Hover state
  • disabled:opacity-50: Disabled state

ARIA Attributes

  • role="navigation": Navigation landmark
  • aria-label="Pagination Navigation": Descriptive label
  • aria-current="page": Marks current page
  • disabled: Disables prev/next when appropriate

Example: Cameroon Cities

$cities = City::where('country', 'Cameroon')
->orderBy('population', 'desc')
->paginate(5);
<table>
<thead>
<tr>
<th>Ville</th>
<th>Région</th>
<th>Population</th>
</tr>
</thead>
<tbody>
@foreach($cities as $city)
<tr>
<td>{{ $city->name }}</td>
<td>{{ $city->region }}</td>
<td>{{ $city->population }}</td>
</tr>
@endforeach
</tbody>
</table>
 
<x-ui.pagination :paginator="$cities" />

Testing

The component includes data-test attributes:

  • data-test="pagination-container": Main container
  • data-test="pagination-info": Results counter
  • data-test="pagination-previous": Previous button
  • data-test="pagination-next": Next button
  • data-test="pagination-pages": Page numbers container
  • data-test="pagination-page": Individual page button
  • data-test="pagination-ellipsis": Ellipsis indicator

Notes

  • Uses wire:click for Livewire navigation
  • No full page reloads
  • Preserves query parameters
  • Mobile responsive design
  • Smooth transitions on state changes

Breadcrumbs Usage

Breadcrumbs Component Usage

A flexible breadcrumb navigation component with icon separators and ARIA accessibility.

Features

  • ✅ Icon-based separators (Lucide icons)
  • ✅ Active page indication (non-clickable)
  • ✅ Flexible item format (array or string)
  • ✅ ARIA accessible navigation
  • ✅ Hover effects on links
  • ✅ Customizable separator icons

Basic Usage

Simple Array Format

<x-ui.breadcrumbs :items="[
['label' => 'Home', 'url' => '/'],
['label' => 'Products', 'url' => '/products'],
['label' => 'Laptop']
]" />

Using 'name' and 'href' Keys

<x-ui.breadcrumbs :items="[
['name' => 'Dashboard', 'href' => '/dashboard'],
['name' => 'Settings', 'href' => '/settings'],
['name' => 'Profile']
]" />

Separator Options

The component uses Lucide icons for separators. Change the separator with the separator prop:

Default (Chevron Right)

<x-ui.breadcrumbs :items="$items" />

Slash Separator

<x-ui.breadcrumbs
separator="slash"
:items="$items"
/>

Circle Separator

<x-ui.breadcrumbs
separator="circle"
:items="$items"
/>

Other Options

Any Lucide icon name works:

  • chevron-right (default)
  • slash
  • circle
  • arrow-right
  • minus
  • chevron-left
  • dot

Dynamic Breadcrumbs

From Route Segments

public function getBreadcrumbsProperty()
{
$segments = request()->segments();
$items = [['label' => 'Home', 'url' => '/']];
 
$path = '';
foreach ($segments as $segment) {
$path .= '/' . $segment;
$items[] = [
'label' => ucfirst($segment),
'url' => $path
];
}
 
return $items;
}
<x-ui.breadcrumbs :items="$this->breadcrumbs" />

From Model Hierarchy

// For a nested category system
public function getBreadcrumbsForCategory($category)
{
$items = [['label' => 'Home', 'url' => '/']];
 
foreach ($category->ancestors as $ancestor) {
$items[] = [
'label' => $ancestor->name,
'url' => route('category.show', $ancestor)
];
}
 
$items[] = ['label' => $category->name];
 
return $items;
}

Real-World Examples

E-commerce Navigation

<x-ui.breadcrumbs :items="[
['label' => 'Home', 'url' => route('home')],
['label' => 'Electronics', 'url' => route('category', 'electronics')],
['label' => 'Laptops', 'url' => route('category.sub', ['electronics', 'laptops'])],
['label' => 'MacBook Pro 14"']
]" />

Administrative Hierarchy (Cameroon Example)

<x-ui.breadcrumbs :items="[
['label' => 'Accueil', 'url' => '/'],
['label' => 'Régions', 'url' => route('regions.index')],
['label' => 'Centre', 'url' => route('regions.show', 'centre')],
['label' => 'Départements', 'url' => route('regions.departments', 'centre')],
['label' => 'Mfoundi']
]" />

Documentation Navigation

<x-ui.breadcrumbs
separator="slash"
:items="[
['label' => 'Docs', 'url' => '/docs'],
['label' => 'Components', 'url' => '/docs/components'],
['label' => 'Navigation', 'url' => '/docs/components/navigation'],
['label' => 'Breadcrumbs']
]"
/>

Settings Navigation

<x-ui.breadcrumbs
separator="arrow-right"
:items="[
['label' => 'Settings', 'url' => route('settings')],
['label' => 'Account', 'url' => route('settings.account')],
['label' => 'Security']
]"
/>

Styling Customization

Custom Classes

<x-ui.breadcrumbs
class="my-4 px-6"
:items="$items"
/>

Within Containers

<div class="bg-muted/30 p-4 rounded-lg">
<x-ui.breadcrumbs :items="$items" />
</div>

Props

Prop Type Required Default Description
items array Yes [] Array of breadcrumb items
separator string No 'chevron-right' Lucide icon name for separator

Item Format

Each item can be:

Object with 'label' and 'url'

['label' => 'Products', 'url' => '/products']

Object with 'name' and 'href'

['name' => 'Products', 'href' => '/products']

Last item (no URL)

['label' => 'Current Page']

ARIA Attributes

  • role="navigation": Navigation landmark
  • aria-label="Breadcrumb": Descriptive label
  • role="list": Ordered list of items
  • aria-current="page": Marks current page

Testing

The component includes data-test attributes:

  • data-test="breadcrumbs-container": Main container
  • data-test="breadcrumb-item": Each breadcrumb item
  • data-test="breadcrumb-link": Clickable links
  • data-test="breadcrumb-current": Current page
  • data-test="breadcrumb-separator": Separator icons

Best Practices

  1. Keep it short: Max 4-5 levels for readability
  2. Use descriptive labels: Clear, concise names
  3. Home first: Start with home/root page
  4. Last item non-clickable: Current page shouldn't link
  5. Mobile consideration: Hide on small screens if needed

Integration with Pagination

<div class="space-y-4">
{{-- Breadcrumb navigation --}}
<x-ui.breadcrumbs :items="[
['label' => 'Dashboard', 'url' => '/'],
['label' => 'Users', 'url' => '/users'],
['label' => 'List']
]" />
 
{{-- Content --}}
@foreach($users as $user)
<div>{{ $user->name }}</div>
@endforeach
 
{{-- Pagination --}}
<x-ui.pagination :paginator="$users" />
</div>

Notes

  • Automatically detects last item (non-clickable)
  • Separator not shown after last item
  • Supports any Lucide icon for separators
  • Hover effects on clickable links
  • Responsive text sizing