owenvoke/blade-entypo
Blade Entypo brings the Entypo icon set to Laravel Blade, offering simple directives for embedding crisp SVG icons in your views. Lightweight and easy to install, it keeps templates clean while giving you quick access to hundreds of scalable icons.
Install.
composer require owenvoke/blade-entypo
Check your framework version first. v2.4.0 raises the constraint to Laravel ^13; that release contains no feature or markup changes, only the composer.json edit. If you are on Laravel 11/12, pin the previous line rather than fighting the resolver:
composer require "owenvoke/blade-entypo:^2.3"
There is nothing else to wire up. The service provider is auto-discovered — no config/app.php entry, no bootstrap/providers.php edit, no asset publishing, no font files. Verify registration before you debug anything else:
php artisan about # check the providers list
php artisan view:clear # if a component "cannot be found" right after install
First use case. Drop an icon into a nav item or page header:
<x-entypo name="home" class="w-6 h-6 text-gray-500" />
Output is inline SVG that inherits currentColor, so sizing and colour are just utility classes — w-6 h-6, text-red-600, hover:text-black. No @font-face, no FOIT, no sprite build step.
Where to look first.
The SVG directory — the source of truth for valid names. Entypo names are frequently non-obvious (arrow-long-left vs arrow-left), so enumerate rather than guess:
ls vendor/owenvoke/blade-entypo/resources/svg | sed 's/\.svg$//' | sort | column -c 100
There are roughly 400 glyphs. Pipe through grep or fzf rather than reading it.
The README for the icon index and the exact tag shape. Confirm this before you template anything — the API is either a name prop (<x-entypo name="home" />) or one anonymous component per file (<x-entypo-home />). Both forms appear in the wild; ls resources/views/components and php artisan view:list settle it in ten seconds.
The service provider if you need to know how the component namespace is registered — that matters for the wrapper pattern below.
The publishable config, only if you need to change a prefix, path, or default class:
php artisan vendor:publish --provider="OwenVoke\BladeEntypo\BladeEntypoServiceProvider"
Before you spread it around, spend twenty minutes on two decisions: build your own <x-icon> alias, and pick an accessibility convention. Both are far cheaper to change now than after sixty templates reference the package directly.
Alias the package behind your own <x-icon>. This is the highest-leverage thing you will do. It makes a future swap to Heroicons or Lucide a one-file change, and it gives you a single place to enforce accessibility defaults and sizing.
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'label' => null])
@if ($label)
<x-entypo
:name="$name"
{{ $attributes->merge(['role' => 'img', 'aria-label' => $label]) }}
/>
@else
<x-entypo
:name="$name"
{{ $attributes->merge(['aria-hidden' => 'true', 'focusable' => 'false']) }}
/>
@endif
Call sites become <x-icon name="home" class="w-5 h-5" /> and <x-icon name="warning" label="Validation error" class="w-4 h-4 text-amber-500" />. Consumers never learn which icon set is underneath. If your version exposes per-file components instead of a name prop, swap the inner tag for <x-dynamic-component :component="'entypo-'.$name" ... /> and keep the rest identical.
Drive names from data, not markup. Because the icon name is a prop, config-driven menus are trivial — no @switch blocks, no interpolation hacks:
@foreach (config('nav.items') as $item)
<a href="{{ route($item['route']) }}" class="flex items-center gap-2">
<x-icon :name="$item['icon']" class="w-4 h-4" />
<span>{{ $item['label'] }}</span>
</a>
@endforeach
Map semantics to glyphs once, in PHP. Status badges, payment methods, file types, and log levels all repeat. Put the mapping in config or an enum method so adding a status is a one-line change instead of a template hunt:
// config/icons.php
return [
'status' => [
'active' => 'check',
'pending' => 'clock',
'failed' => 'cross',
],
];
<x-icon :name="config('icons.status.'.$model->status)" class="w-4 h-4" />
Icons in buttons and links. The visible label carries the meaning; the glyph is decoration. Never rely on the icon alone unless the surrounding control has its own accessible name:
<button class="inline-flex items-center gap-2">
<x-icon name="trash" class="w-4 h-4" />
<span>Delete</span>
</button>
{{-- Icon-only: the button carries the accessible name --}}
<button aria-label="Close panel" class="p-2">
<x-icon name="cross" class="w-4 h-4" />
</button>
Watch DOM weight in dense listings. Every icon is a real inline <svg> in the response. A 200-row table with three icons per row is 600 SVGs on the wire. That is usually acceptable, but measure before assuming — if payload or node count shows up in profiling, reserve icons for summary/row-detail views and drop them from index tables.
Livewire and Inertia. Blade-shell apps, Livewire components, and server-rendered Inertia pages all work naturally: icons render server-side and arrive as markup. Inside Vue/React SFCs they are unavailable, so keep those surfaces on their own SVG pipeline instead of duplicating the icon set by hand.
Migrating off a webfont. Replace <i class="entypo-*"> with components, verify visually, then delete the icon font files, the @font-face declarations, and the icon-font CSS. That deletion is the tangible win from adopting this package — fewer bytes on first paint and no invisible-text flash.
Testing. Assert on rendered output rather than through a full HTTP round trip:
$html = Blade::render('<x-icon name="home" />');
$this->assertStringContainsString('aria-hidden="true"', $html);
$this->assertStringContainsString('<svg', $html);
For a page-level smoke test, use $response->assertSee('<svg', false) — the second argument disables escaping.
The version constraint is the real gate. v2.4.0 is only a Laravel ^13 bump — no features, no fixes, no markup changes. Before upgrading, read the diff of composer.json and check whether the constraint widened (added ^13 alongside earlier majors) or replaced them, and what the new PHP floor is. A framework-constraint release is exactly the class of change that forces a transitive downgrade in your lockfile. Resolve it in a throwaway branch first.
A typo in an icon name is the most common failure. You get a Blade component-not-found exception, not a silent fallback:
Unable to locate a class or view for component [entypo-arow-left].
The fix is always the same: check the filename in resources/svg. Keep the sorted list bookmarked during initial adoption, and add a unit test that renders every name in your config/icons.php map.
currentColor only helps if the SVG uses it. Some glyphs in icon sets ship with hardcoded fills, in which case text-* classes silently do nothing. If a colour will not apply, inspect the rendered markup before blaming Tailwind's purge.
Class merging is order-dependent. Attribute pass-through concatenates your class string with anything the component or your alias defines. If a default size wins over yours, inspect the final class attribute in devtools and fix the ordering — do not reach for !important.
Clear compiled views after deploy. Anonymous components resolve at view-compile time. If a newly added icon does not appear in production, the usual suspect is a stale compiled view:
php artisan view:cache # in the deploy script
php artisan optimize:clear # locally, when something looks impossible
Accessibility is entirely your responsibility. The package supplies no labels, no role, and no title slot guarantees. Every icon needs a decision: decorative (aria-hidden="true" + focusable="false") or meaningful (role="img" + aria-label). Enforce that in <x-icon> so it cannot be forgotten, and check contrast for icons that carry meaning on their own.
Licensing will block you later if you ignore it now. The wrapper is MIT; the Entypo artwork is generally published under CC BY-SA, which carries attribution and share-alike obligations. MIT on the package does not relicense the glyphs. Add a NOTICE/LICENSES entry and decide on an attribution placement (credits page or footer) at adoption time — not after a legal review stalls a release.
The glyph set is frozen. Entypo has not meaningfully grown since the early 2010s. Missing icons are not coming upstream. When you need one, add it as your own component alongside the alias (a resources/views/components/icon/custom-*.blade.php plus a branch in <x-icon>) rather than forking the package.
Inline SVG and CSP. If you run a Content-Security-Policy, inline <svg> is fine — it is markup, not an external resource — but any inline <style> or fill="url(#...)" referencing a gradient defined elsewhere can trip stricter policies. Check the rendered markup if icons render blank in an environment with a hardened CSP.
One maintainer, seven stars, zero dependents. The surface area is tiny — a provider plus a directory of SVGs — so vendoring or forking is a one-day job if Packagist ever goes quiet. The <x-icon> wrapper is what keeps that cost at one day; direct package-tag usage across sixty templates is what makes it expensive.
Do not mix icon sources ad hoc. If half the app uses these components and half uses raw SVGs pasted from a design tool, you get inconsistent optical sizing, two sizing conventions, and two migration paths later. Pick one path, funnel everything through <x-icon>, and enforce it in code review.
How can I help you explore Laravel packages today?