eduard9969/blade-polaris-icons
A Laravel Blade package for rendering Shopify Polaris icons as simple, reusable components. Add clean, customizable SVG icons to your views with concise Blade tags, keeping markup tidy and consistent across your application.
composer require eduard9969/blade-polaris-icons
The package is auto-discovered — no service provider registration needed in bootstrap/providers.php. As of 2.9.0 it supports Laravel 13, so the constraint now covers the current framework line; if you are pinned to an older Laravel, check the composer.json of the tagged release before upgrading.
Where to look first:
README.md on GitHub for the exact component/directive name and prop list (naming has stayed stable, but confirm before mass-replacing markup).src/ for the Blade component class — this is where prop defaults and the icon-name → SVG lookup live.resources/views/ for the template, if you need to override markup or the wrapper element.config/ — publish only if the package exposes a config (php artisan vendor:publish --tag=polaris-icons-config); most installs need nothing.First use case — drop an icon into an existing view:
<x-polaris-icon name="AddMajor" class="w-5 h-5" />
Render it next to a button label, check that the SVG inherits currentColor, and you have the whole loop: the package is essentially a Blade front-end to the Shopify Polaris icon set.
Design-system wrapper. Don't sprinkle the vendor component across hundreds of views. Wrap it once so you can swap the implementation, enforce sizing, and centralise accessibility:
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'md'])
<x-polaris-icon
:name="$name"
{{ $attributes->merge([
'class' => match($size) {
'sm' => 'w-4 h-4',
'lg' => 'w-6 h-6',
default => 'w-5 h-5',
},
'aria-hidden' => 'true',
]) }}
/>
Data-driven icons (navigation, menus, resource tables). Map your domain values to Polaris names rather than passing raw strings from the database straight through — an invalid icon name yields nothing useful, and unsanitised input into a component prop is a needless surface.
// config/navigation.php
return [
['label' => 'Orders', 'route' => 'orders.index', 'icon' => 'OrderIcon'],
['label' => 'Products','route' => 'products.index','icon' => 'ProductIcon'],
];
@foreach (config('navigation') as $item)
<a href="{{ route($item['route']) }}" @class(['nav-link', 'active' => request()->routeIs($item['route'])])>
<x-icon :name="$item['icon']" size="sm" />
{{ $item['label'] }}
</a>
@endforeach
Composition with slots and other components. Icons are leaf components, so they slot naturally into buttons, badges, and empty states:
<x-polaris-button variant="primary">
<x-icon name="ImportIcon" size="sm" class="mr-2" />
Import products
</x-polaris-button>
Conditional and state-driven icons. Because output is inline SVG and inherits currentColor, hover/disabled/active states come free from your CSS — no per-state asset juggling:
<x-icon :name="$sortDirection === 'asc' ? 'ArrowUpIcon' : 'ArrowDownIcon'" />
Testing. Assert on the rendered output in feature tests rather than unit-testing the component. A simple assertSee('svg', false) on a page-level test catches the common failure mode of a renamed icon or a missing view namespace after an upgrade.
AddMajor, ArrowUpIcon, OrderIcon — casing matters. A typo usually renders an empty wrapper, not an exception, so a broken icon can slip past CI. Add one smoke test per icon you reference in config.currentColor is the contract. If an icon looks invisible, it's almost always a white/transparent text colour on the parent, not a package bug. Set colour on the wrapper, not on the SVG.{{ $attributes->merge([...]) }} in your wrapper. Passing class directly to the vendor component and to your wrapper will silently drop one depending on merge order.<svg>. A dense table with an icon per row across 100 rows adds real bytes. If you have hot, icon-heavy pages, consider rendering a <use>-based sprite yourself instead of inlining per row, or cache aggressively.php artisan view:cache after deploy. Since icons are compiled Blade, a stale view cache after bumping the package is a classic "new icons missing in prod but fine locally" cause.composer.json moves. On a multi-app monorepo, don't assume one resolved version works everywhere — check each app's lock file when you upgrade Laravel.aria-hidden="true"; meaningful icons need an accessible label on the parent control. Bake this into your wrapper rather than remembering per usage — the merge pattern above is the right place.x-icon wrapper means that swap is one file.How can I help you explore Laravel packages today?