Blade/Livewire Coding Guidelines
This guide documents coding standards and best practices for Blade templates and Livewire components.
Blade Template Conventions
File Naming
- Use kebab-case:
item-translation.blade.php - Partials start with underscore:
_form.blade.php - Layout files describe their purpose:
form-page.blade.php
Template Structure
{{-- Comments --}}
@extends('layouts.app')
@section('content')
<div class="container">
{{-- Template content --}}
</div>
@endsection
Avoid Shorthand Notation
Critical: Do not use shorthand component notation as it can cause parsing issues.
<!-- Good: Full syntax -->
<x-slot name="header">Header Content</x-slot>
<!-- Bad: Shorthand -->
<x-slot:header>Header Content</x-slot:header>
Variable Usage in Components
Use variables instead of string interpolation to avoid nesting issues:
<!-- Good: Variable -->
@php($routePrefix = 'items')
<x-component :route="$routePrefix . '.create'" />
<!-- Bad: String interpolation in component -->
<x-component route="{{ $entity }}.create" />
Blade Directives
Control Structures
@if($condition)
{{-- Content --}}
@elseif($otherCondition)
{{-- Content --}}
@else
{{-- Content --}}
@endif
@foreach($items as $item)
{{ $item->name }}
@endforeach
@forelse($items as $item)
{{ $item->name }}
@empty
<p>No items found.</p>
@endforelse
Authentication
@auth
{{-- User is authenticated --}}
@endauth
@guest
{{-- User is not authenticated --}}
@endguest
Authorization
@can(\App\Enums\Permission::VIEW_DATA->value)
<a href="{{ route('items.index') }}">View Items</a>
@endcan
@cannot(\App\Enums\Permission::DELETE_DATA->value)
<p>You cannot delete items.</p>
@endcannot
PHP in Blade
Keep PHP blocks at the top of sections:
@section('content')
@php($c = $entityColor('items'))
@php($title = 'Items List')
<div class="{{ $c['bg'] }}">
<h1>{{ $title }}</h1>
</div>
@endsection
Don’t nest @php blocks inside control structures:
<!-- Bad: PHP block inside @if -->
@if($condition)
@php($variable = 'value')
{{ $variable }}
@endif
<!-- Good: PHP block before control structure -->
@php($variable = $condition ? 'value' : 'default')
@if($condition)
{{ $variable }}
@endif
Component Development
Component Properties
Document component props with @props:
@props([
'entity' => '',
'title' => '',
'backRoute' => '',
])
Default Values
Provide sensible defaults:
@props([
'size' => 'md',
'variant' => 'primary',
'entity' => null,
])
Required vs Optional
Use prop validation for required props:
@props([
'entity', // Required (no default)
'title' => '', // Optional (has default)
])
Slots
Use named slots for complex components:
<x-modal>
<x-slot name="title">Modal Title</x-slot>
<x-slot name="content">Modal Content</x-slot>
<x-slot name="footer">Modal Footer</x-slot>
</x-modal>
Livewire Component Conventions
Component Structure
class ItemsTable extends Component
{
use WithPagination;
// Public properties (wire:model)
public $sortField = 'created_at';
public $sortDirection = 'desc';
public $search = '';
// Query string parameters
protected $queryString = [
'search' => ['except' => ''],
'sortField' => ['except' => 'created_at'],
];
// Methods
public function sortBy($field)
{
// Logic
}
public function render()
{
return view('livewire.tables.items-table', [
'items' => $this->getItems(),
]);
}
}
Property Naming
- Use camelCase:
$sortField,$searchQuery - Boolean prefixes:
$isActive,$hasItems - Collections suffix:
$items,$users
Lifecycle Hooks
public function mount()
{
// Called when component is initialized
}
public function updated($propertyName)
{
// Called when any property is updated
}
public function updatedSearch()
{
// Called when specific property is updated
$this->resetPage();
}
Entity Color System
Always use the entity color helper:
@php($c = $entityColor('items'))
<div class="{{ $c['bg'] }}">Background</div>
<a href="#" class="{{ $c['accentLink'] }}">Link</a>
<button class="{{ $c['button'] }}">Button</button>
Available Color Properties
bg- Background colortext- Text colorbutton- Button stylingbadge- Badge/pill stylingaccentLink- Link stylingborderColor- Border colorhoverBg- Hover background
Styling Conventions
Tailwind Classes
- Use utility classes directly in templates
- Order classes logically: layout → sizing → spacing → colors → typography
- Use responsive prefixes:
sm:,md:,lg:
Class Order Example
<div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-sm hover:shadow-md">
Responsive Design
<div class="flex flex-col sm:flex-row gap-4">
<!-- Mobile: stacked, Desktop: horizontal -->
</div>
<td class="hidden lg:table-cell px-4 py-3">
<!-- Hidden on mobile, visible on desktop -->
</td>
Error Handling
Validation Errors
Display validation errors automatically with form components:
<x-form.field label="Name" name="internal_name">
<x-form.input name="internal_name" :value="old('internal_name')" />
</x-form.field>
Flash Messages
Show success/error messages:
@if(session('status'))
<x-ui.alert :message="session('status')" type="success" entity="items" />
@endif
Performance
Eager Loading
Prevent N+1 queries:
$items = Item::with(['partner', 'country', 'translations'])->get();
Pagination
Always paginate large datasets:
$items = Item::paginate(15);
Livewire Lazy Loading
<livewire:items-table lazy />
Security
Mass Assignment Protection
Define fillable or guarded in models:
protected $fillable = ['internal_name', 'type'];
CSRF Protection
Always include CSRF token in forms:
<form method="POST">
@csrf
</form>
Authorization
Check permissions in views:
@can(\App\Enums\Permission::CREATE_DATA->value)
<a href="{{ route('items.create') }}">Add Item</a>
@endcan
Best Practices
- DRY Principle - Extract reusable components and partials
- Entity Colors - Use color system for consistency
- Responsive Design - Mobile-first approach
- Accessibility - Semantic HTML, ARIA labels, keyboard navigation
- Performance - Eager loading, pagination, caching
- Security - CSRF tokens, authorization, validation
- Testing - Write tests for components and workflows
- Documentation - Comment complex logic