Laravel Permission provides custom Blade directives that make it easy to show or hide content based on user permissions and roles. These directives are cleaner and more readable than using @if statements with method calls.
Permission Directives
Check user permissions directly in your Blade templates.
@haspermission
Show content only if the user has a specific permission:
@haspermission ( 'edit articles' )
< a href = " {{ route ('articles.edit', $article ) }} " class = "btn btn-primary" >
Edit Article
</ a >
@endhaspermission
Basic Usage
With Else
Specific Guard
@haspermission ( 'delete articles' )
< form action = " {{ route ('articles.destroy', $article ) }} " method = "POST" >
@csrf
@method ( ' DELETE ' )
< button type = "submit" class = "btn btn-danger" > Delete </ button >
</ form >
@endhaspermission
@haspermission ( 'edit articles' )
< a href = " {{ route ('articles.edit', $article ) }} " > Edit </ a >
@else
< span class = "text-muted" > View Only </ span >
@endhaspermission
@haspermission ( 'edit articles' , 'api' )
< button > Edit via API </ button >
@endhaspermission
Behind the scenes : The @haspermission directive calls auth()->user()->checkPermissionTo($permission), which returns false gracefully if the permission doesn’t exist.
Role Directives
Show or hide content based on user roles.
@role
Show content only if the user has a specific role:
@role ( 'admin' )
< a href = " {{ route ('admin.dashboard') }} " class = "nav-link" >
Admin Dashboard
</ a >
@endrole
Single Role
With Else
Specific Guard
@role ( 'writer' )
< div class = "alert alert-info" >
Welcome, Writer! You can create and edit articles.
</ div >
@endrole
@role ( 'admin' )
< button class = "btn btn-danger" > Delete User </ button >
@else
< button class = "btn btn-secondary" disabled > No Permission </ button >
@endrole
@role ( 'admin' , 'api' )
< span class = "badge badge-success" > API Admin </ span >
@endrole
@hasrole
Alias to @role - works identically:
@hasrole ( 'editor' )
< a href = " {{ route ('articles.pending') }} " >
Pending Articles ( {{ $pendingCount }} )
</ a >
@endhasrole
@hasrole and @role are functionally identical. Use whichever reads better in your templates.
@hasanyrole
Show content if user has any of the specified roles:
@hasanyrole ( 'writer|editor|admin' )
< div class = "content-management-panel" >
< h3 > Content Management </ h3 >
<!-- Content management tools -->
</ div >
@endhasanyrole
@hasanyrole ( 'writer|editor' )
< a href = " {{ route ('articles.create') }} " > Create Article </ a >
@endhasanyrole
@hasanyrole ( 'admin|super-admin' )
< button class = "btn btn-danger" > Delete </ button >
@else
< span class = "text-muted" > Admin only </ span >
@endhasanyrole
@hasallroles
Show content only if user has all specified roles:
@hasallroles ( 'writer|reviewer' )
< div class = "alert alert-success" >
You can write and review articles!
</ div >
@endhasallroles
User must have ALL roles listed. If they’re missing even one, the content won’t show.
@hasexactroles
Show content only if user has exactly these roles (no more, no less):
@hasexactroles ( 'writer|editor' )
< p > You have exactly the Writer and Editor roles. </ p >
@endhasexactroles
This directive checks that the user has precisely these roles and no others.
Using Laravel’s Native @can Directive
Laravel Permission integrates with Laravel’s built-in authorization, so @can works seamlessly:
@can ( 'edit articles' )
< a href = " {{ route ('articles.edit', $article ) }} " > Edit </ a >
@endcan
@can ( 'delete articles' )
< button type = "submit" class = "btn btn-danger" > Delete </ button >
@endcan
With @cannot
@cannot
@canany
@can ( 'edit articles' )
< a href = " {{ route ('articles.edit', $article ) }} " > Edit </ a >
@elsecan ( 'view articles' )
< a href = " {{ route ('articles.show', $article ) }} " > View </ a >
@else
< span class = "text-muted" > No access </ span >
@endcan
@cannot ( 'delete articles' )
< div class = "alert alert-warning" >
You don't have permission to delete articles.
</ div >
@endcannot
@canany ([ 'edit articles' , 'delete articles' ])
< div class = "admin-tools" >
<!-- Admin tools here -->
</ div >
@endcanany
Practical Examples
< nav class = "navbar" >
< ul class = "nav" >
< li >< a href = " {{ route ('home') }} " > Home </ a ></ li >
@role ( 'writer|editor|admin' )
< li >< a href = " {{ route ('articles.index') }} " > Articles </ a ></ li >
@endrole
@can ( 'create articles' )
< li >< a href = " {{ route ('articles.create') }} " > New Article </ a ></ li >
@endcan
@role ( 'admin' )
< li >< a href = " {{ route ('admin.users') }} " > Users </ a ></ li >
< li >< a href = " {{ route ('admin.roles') }} " > Roles </ a ></ li >
@endrole
</ ul >
</ nav >
Article Action Buttons
< div class = "article-actions" >
@can ( 'view articles' )
< a href = " {{ route ('articles.show', $article ) }} " class = "btn btn-info" >
View
</ a >
@endcan
@can ( 'edit articles' )
< a href = " {{ route ('articles.edit', $article ) }} " class = "btn btn-primary" >
Edit
</ a >
@endcan
@can ( 'delete articles' )
< form action = " {{ route ('articles.destroy', $article ) }} " method = "POST" class = "d-inline" >
@csrf
@method ( ' DELETE ' )
< button type = "submit" class = "btn btn-danger"
onclick = " return confirm ('Are you sure?')" >
Delete
</ button >
</ form >
@endcan
@role ( 'admin' )
< a href = " {{ route ('articles.audit', $article ) }} " class = "btn btn-secondary" >
Audit Log
</ a >
@endrole
</ div >
User Dashboard
< div class = "dashboard" >
< h1 > Dashboard </ h1 >
@hasanyrole ( 'writer|editor' )
< div class = "card" >
< h3 > Your Articles </ h3 >
< p > You have {{ $articleCount }} articles </ p >
< a href = " {{ route ('articles.mine') }} " > View My Articles </ a >
</ div >
@endhasanyrole
@role ( 'editor' )
< div class = "card" >
< h3 > Pending Review </ h3 >
< p > {{ $pendingCount }} articles awaiting review </ p >
< a href = " {{ route ('articles.pending') }} " > Review Articles </ a >
</ div >
@endrole
@role ( 'admin' )
< div class = "card" >
< h3 > System Stats </ h3 >
< ul >
< li > Total Users: {{ $userCount }} </ li >
< li > Total Articles: {{ $totalArticles }} </ li >
< li > Active Sessions: {{ $activeSessions }} </ li >
</ ul >
</ div >
@endrole
</ div >
Admin Settings
< div class = "settings" >
< h2 > Settings </ h2 >
@haspermission ( 'edit settings' )
< form action = " {{ route ('settings.update') }} " method = "POST" >
@csrf
<!-- Settings form -->
< button type = "submit" class = "btn btn-primary" > Save Settings </ button >
</ form >
@elsehaspermission
< div class = "alert alert-info" >
Settings are view-only. Contact an administrator to make changes.
</ div >
<!-- Read-only settings display -->
@endhaspermission
</ div >
How Directives Work
The directives are registered in the PermissionServiceProvider:
// From: src/PermissionServiceProvider.php:68-82
protected function registerBladeExtensions ( BladeCompiler $bladeCompiler ) : void
{
$bladeMethodWrapper = ' \\ Spatie \\ Permission \\ PermissionServiceProvider::bladeMethodWrapper' ;
// Permission checks
$bladeCompiler -> if ( 'haspermission' ,
fn () => $bladeMethodWrapper ( 'checkPermissionTo' , ... func_get_args ())
);
// Role checks
$bladeCompiler -> if ( 'role' ,
fn () => $bladeMethodWrapper ( 'hasRole' , ... func_get_args ())
);
$bladeCompiler -> if ( 'hasrole' ,
fn () => $bladeMethodWrapper ( 'hasRole' , ... func_get_args ())
);
$bladeCompiler -> if ( 'hasanyrole' ,
fn () => $bladeMethodWrapper ( 'hasAnyRole' , ... func_get_args ())
);
$bladeCompiler -> if ( 'hasallroles' ,
fn () => $bladeMethodWrapper ( 'hasAllRoles' , ... func_get_args ())
);
$bladeCompiler -> if ( 'hasexactroles' ,
fn () => $bladeMethodWrapper ( 'hasExactRoles' , ... func_get_args ())
);
}
The bladeMethodWrapper helper:
// From: src/PermissionServiceProvider.php:63-66
public static function bladeMethodWrapper ( string $method , mixed $role , ? string $guard = null ) : bool
{
return auth ( $guard ) -> check () && auth ( $guard ) -> user () -> { $method }( $role );
}
All directives automatically check if the user is authenticated. If there’s no authenticated user, they return false.
Best Practices
Use @can for permissions : Prefer @can over @haspermission as it’s Laravel’s standard and works with policies too.<!-- Preferred -->
@can ( 'edit articles' )
< button > Edit </ button >
@endcan
<!-- Also works -->
@haspermission ( 'edit articles' )
< button > Edit </ button >
@endhaspermission
Combine with policies : Use directives for simple checks, policies for complex logic:{{-- Simple permission check --}}
@can ( 'edit articles' )
< button > Edit Any Article </ button >
@endcan
{{-- Complex check using policy --}}
@can ( 'update' , $article )
< button > Edit This Article </ button >
@endcan
Don’t rely solely on Blade directives for security . Always validate permissions on the backend. Blade directives only control what’s displayed, not what users can access.
Next Steps
Using Middleware Protect routes with permission middleware
Multiple Guards Use permissions with different authentication guards