Day 8 - Component Challenge

Challenge UI with Livewire & Alpine.js

Day 8

Day 8

Skeleton Loader & Avatar

Skeleton Loader

Loading state component to improve perceived user experience.

Features:

  • Pulse animation (native Tailwind)
  • Predefined variants (text, title, avatar, card)
  • Customizable sizes
  • Support wire:loading
  • Accessible (aria-hidden)

Basic Variants

Text:
Title:
Avatar:
Avatar SM:
Avatar LG:
Button:

Paragraph

Multiple Lines

Card Skeleton

Custom Sizes

Avatar & Avatar Group

Identity display component with automatic fallback handling.

Features:

  • Automatic fallback (initials or icon)
  • Status indicator (online, offline, busy, away)
  • Multiple sizes (xs to 2xl)
  • Shapes (circle, square, rounded)
  • Avatar Group with +X badge

Sizes

Ngono Marie xs
Mbarga Paul sm
Fotso Jean md
Nkeng Carine lg
Tchinda Roger xl
Biya Sandrine 2xl

Shapes

Circle circle
Rounded rounded
Square square

Fallback States

KA Initials
JE Short name
Default
Eyenga Rose Invalid image

Status Indicators

Online online
Offline offline
Busy busy
Away away

Avatar Group

Default (max 4):
Ngono Marie
Mbarga Paul
Fotso Jean
Nkeng Carine
+4
Max 3:
Ngono Marie
Mbarga Paul
Fotso Jean
+5
Large size:
Ngono Marie
Mbarga Paul
Fotso Jean
Nkeng Carine
Tchinda Roger
+3
Square shape:
Ngono Marie
Mbarga Paul
Fotso Jean
Nkeng Carine
+4

Interactive Demo

User Profile - Loading simulation

Click to toggle between loading state and content

Development Team

Usage Examples

Skeleton Usage

Skeleton Loader Component

Le composant <x-ui.skeleton> affiche un placeholder animé pendant le chargement. 100% Tailwind CSS.

Basic Usage

<x-ui.skeleton />

Variants

{{-- Text line --}}
<x-ui.skeleton variant="text" />
 
{{-- Title (larger, 75% width) --}}
<x-ui.skeleton variant="title" />
 
{{-- Avatar sizes --}}
<x-ui.skeleton variant="avatar" />
<x-ui.skeleton variant="avatar-sm" />
<x-ui.skeleton variant="avatar-lg" />
 
{{-- Button --}}
<x-ui.skeleton variant="button" />
 
{{-- Card/Image --}}
<x-ui.skeleton variant="card" />
<x-ui.skeleton variant="image" />
 
{{-- Thumbnail --}}
<x-ui.skeleton variant="thumbnail" />

Multiple Lines

{{-- Generate 4 text lines --}}
<x-ui.skeleton variant="text" :count="4" />
 
{{-- With custom gap --}}
<x-ui.skeleton variant="text" :count="3" gap="4" />

Custom Sizes (Tailwind Classes)

{{-- Square 96px --}}
<x-ui.skeleton class="size-24" rounded="lg" />
 
{{-- Custom width/height --}}
<x-ui.skeleton class="w-36 h-5" />
 
{{-- Circle 80px --}}
<x-ui.skeleton class="size-20" rounded="full" />
 
{{-- Full width, fixed height --}}
<x-ui.skeleton class="w-full h-12" />

Rounded Options

<x-ui.skeleton rounded="none" />
<x-ui.skeleton rounded="sm" />
<x-ui.skeleton rounded="md" /> {{-- default --}}
<x-ui.skeleton rounded="lg" />
<x-ui.skeleton rounded="xl" />
<x-ui.skeleton rounded="full" />

With Livewire wire:loading

<div>
{{-- Show skeleton during loading --}}
<div wire:loading>
<x-ui.skeleton variant="title" />
<x-ui.skeleton variant="text" :count="3" />
</div>
 
{{-- Show content when loaded --}}
<div wire:loading.remove>
<h2>{{ $title }}</h2>
<p>{{ $content }}</p>
</div>
</div>

Card Loading Example

<div class="p-4 border rounded-lg">
<x-ui.skeleton variant="image" class="mb-4" />
<x-ui.skeleton variant="title" class="mb-2" />
<x-ui.skeleton variant="text" :count="2" />
<x-ui.skeleton variant="button" class="mt-4" />
</div>

Props Reference

Prop Type Default Description
variant string default Predefined variant (text, title, avatar, button, card, image, thumbnail)
rounded string md Border radius (none, sm, md, lg, xl, full)
count int 1 Number of skeleton items to render
gap string 2 Gap between items when count > 1 (1-6)
class string '' Custom Tailwind classes for sizing

Testing Attributes

Attribute Description
data-test="skeleton-item" Individual skeleton element
data-test="skeleton-group" Container when count > 1

Avatar Usage

Avatar Component

Le composant <x-ui.avatar> affiche l'image de profil d'un utilisateur avec fallback automatique.

Basic Usage

{{-- With image --}}
<x-ui.avatar src="https://example.com/avatar.jpg" name="Ngono Marie" />
 
{{-- With name only (shows initials) --}}
<x-ui.avatar name="Ngono Marie" />
 
{{-- Default (shows user icon) --}}
<x-ui.avatar />

Sizes

<x-ui.avatar size="xs" name="XS" /> {{-- 24px --}}
<x-ui.avatar size="sm" name="SM" /> {{-- 32px --}}
<x-ui.avatar size="md" name="MD" /> {{-- 40px (default) --}}
<x-ui.avatar size="lg" name="LG" /> {{-- 48px --}}
<x-ui.avatar size="xl" name="XL" /> {{-- 56px --}}
<x-ui.avatar size="2xl" name="2XL" /> {{-- 64px --}}

Shapes

{{-- Circle (default) --}}
<x-ui.avatar shape="circle" name="Circle" />
 
{{-- Rounded square --}}
<x-ui.avatar shape="rounded" name="Rounded" />
 
{{-- Square --}}
<x-ui.avatar shape="square" name="Square" />

Status Indicators

<x-ui.avatar status="online" name="Online" /> {{-- Green dot --}}
<x-ui.avatar status="offline" name="Offline" /> {{-- Gray dot --}}
<x-ui.avatar status="busy" name="Busy" /> {{-- Red dot --}}
<x-ui.avatar status="away" name="Away" /> {{-- Yellow dot --}}

Fallback Behavior

{{-- Image loads successfully --}}
<x-ui.avatar src="valid-url.jpg" name="User Name" />
 
{{-- Image fails - shows initials from name --}}
<x-ui.avatar src="invalid-url.jpg" name="User Name" />
 
{{-- No image, has name - shows initials --}}
<x-ui.avatar name="User Name" />
 
{{-- No image, no name - shows default icon --}}
<x-ui.avatar />
 
{{-- Custom fallback icon --}}
<x-ui.avatar fallbackIcon="users" />

Avatar Props Reference

Prop Type Default Description
src string null Image URL
alt string '' Image alt text
name string null User name (used for initials fallback)
size string md Size (xs, sm, md, lg, xl, 2xl)
shape string circle Shape (circle, square, rounded)
status string null Status indicator (online, offline, busy, away)
fallbackIcon string user Lucide icon name for default fallback

Avatar Group Component

Le composant <x-ui.avatar-group> affiche plusieurs avatars empilés avec un badge +X.

Basic Usage

@php
$users = [
['name' => 'User 1', 'src' => 'avatar1.jpg'],
['name' => 'User 2', 'src' => 'avatar2.jpg'],
['name' => 'User 3', 'src' => 'avatar3.jpg'],
['name' => 'User 4', 'src' => 'avatar4.jpg'],
['name' => 'User 5', 'src' => 'avatar5.jpg'],
];
@endphp
 
<x-ui.avatar-group :avatars="$users" />

Maximum Displayed

{{-- Show max 3 avatars, rest as +X --}}
<x-ui.avatar-group :avatars="$users" :max="3" />
 
{{-- Show max 6 avatars --}}
<x-ui.avatar-group :avatars="$users" :max="6" />

With Status

@php
$team = [
['name' => 'Alice', 'src' => 'alice.jpg', 'status' => 'online'],
['name' => 'Bob', 'src' => 'bob.jpg', 'status' => 'busy'],
['name' => 'Carol', 'src' => 'carol.jpg', 'status' => 'away'],
];
@endphp
 
<x-ui.avatar-group :avatars="$team" />

Size and Shape

{{-- Large avatars --}}
<x-ui.avatar-group :avatars="$users" size="lg" />
 
{{-- Square shape --}}
<x-ui.avatar-group :avatars="$users" shape="square" />
 
{{-- Small with rounded shape --}}
<x-ui.avatar-group :avatars="$users" size="sm" shape="rounded" />

Avatar Array Format

@php
// Full format
$users = [
[
'name' => 'User Name', // For initials fallback
'src' => 'image-url.jpg', // or 'image' key
'alt' => 'Alt text', // Optional
'status' => 'online', // Optional
],
];
 
// Simple format (image URL only)
$users = [
'avatar1.jpg',
'avatar2.jpg',
'avatar3.jpg',
];
@endphp

Avatar Group Props Reference

Prop Type Default Description
avatars array [] Array of avatar data
max int 4 Maximum avatars to display
size string md Avatar size (xs, sm, md, lg, xl, 2xl)
shape string circle Avatar shape (circle, square, rounded)
spacing string -2 Overlap spacing (Tailwind margin)

Testing Attributes

Attribute Description
data-test="avatar-container" Avatar wrapper element
data-test="avatar-image" Avatar image element
data-test="avatar-initials" Initials fallback text
data-test="avatar-icon" Icon fallback element
data-test="avatar-fallback" Hidden fallback container
data-test="avatar-status" Status indicator dot
data-test="avatar-group" Avatar group container
data-test="avatar-group-item" Individual avatar in group
data-test="avatar-group-overflow" +X overflow badge
data-test="avatar-group-count" Count text in overflow badge