codeat3/blade-codicons
Blade Codicons brings VS Code's Codicon icon set to your Laravel Blade views as simple, fluent components. Render crisp, themeable SVG icons with a clean tag syntax, ideal for dashboards, editors, and any project needing lightweight scalable icons.
Architecture fit. This is a presentation-layer-only dependency: a Laravel service provider that auto-registers a generated set of Blade components (<x-codicon-save />) rendering inline SVG from resources/views/components/ inside vendor/. There is no runtime JS, no asset pipeline coupling, no database surface, no queue or job interaction, and no state. It composes cleanly with Blade layouts, @included partials, and Livewire views — Livewire morphing is a non-issue because output is deterministic server-rendered markup. The one genuinely architectural decision it forces is ours, not the package's: whether <x-codicon-*> appears directly in views or is absorbed behind a local <x-icon name="..." /> wrapper. That choice determines whether a future vendor swap is a one-file change or an N-file refactor.
Integration feasibility. Low effort, fast to prove. composer require codeat3/blade-codicons:^1.35, nothing to publish, no config, no Vite/Tailwind changes. Version 1.35.0 is the floor if Laravel 13 is in play — the release is compatibility-only (PR #51), no API change, no new glyphs, no deprecations. First render is a same-day demo: two tags in a layout, one screenshot. The real work is not installation but the two governance artifacts we should require before icon #2 ships: the wrapper component and a name-mapping config (config/icons.php) so product vocabulary (delete) is decoupled from vendor vocabulary (trash).
Technical risk. Three risks are material and all are cheap to mitigate:
Unable to locate a class or view for component at render time — a hard 500 on whatever page needed it, not a blank box. Because the set is auto-generated from Microsoft's upstream on a fast patch cadence, renames flow straight into component names. Mitigation: pin the version tightly, plus a CI smoke test ($this->blade('<x-codicon-save />')->assertSee('<svg', false)) and a test asserting every name in config/icons.php renders.aria-hidden, so every icon enters the accessibility tree as an unlabeled graphic unless the wrapper bakes in aria-hidden="true" focusable="false" for decorative use and role="img" aria-label="..." for icon-only controls. This is an audit finding waiting to happen if we skip the wrapper.Secondary risks worth naming but not blocking: inline SVG inflates HTML on icon-dense screens (a 200-row table × 3 action icons is a six-figure byte count — measure one real screen during the pilot); currentColor means any ancestor setting text-transparent (clip-text headings, some skeleton loaders) silently erases the icon; and inline SVG is stripped by most mail clients, so this must not reach email templates.
Key questions to close before approving fleet-wide.
composer why-not codeat3/blade-codicons)$attributes onto the <svg> itself, or does class land on a wrapper? This decides the wrapper's internals and should be verified in vendor/, not the README.view:cache run relative to composer install?Stack fit. Appropriate for Laravel 12–13 applications with Blade-rendered internal surfaces: admin consoles, dev-tools dashboards, log viewers, CI/observability panels, code-review or diff UIs, settings and toolbar chrome. Codicons read as native in exactly that register and as borrowed on consumer or marketing pages, so the fit is a segmentation decision we should own explicitly rather than let drift screen by screen. It is a poor fit for React/Vue/Inertia frontends — there the upstream Codicons npm package is the right input and this wrapper adds nothing.
Migration path. Incremental, reversible, no downtime, no data migration. Screen by screen: inventory existing inline SVGs → map each to a Codicon name in config/icons.php → replace with <x-icon> → delete the old partial. Each screen is its own commit and independently revertable. Run the visual pass on global nav and shared layout chrome first, because an icon that renders fine in a table but throws in the shared layout takes the whole app down. Not in scope for migration: email templates and any icon set that design has art-directed.
Compatibility. Requires care in two specific places. First, version pinning: the auto-generated nature means a patch bump can rename components, so pin ("1.35.0" or a tight caret) and gate bumps behind the CI tests rather than letting composer update move it silently. Second, compiled views: components live in vendor/, so any deploy running php artisan view:cache must do so after composer install; stale compiled views after an upgrade produce "component not found" errors that are easy to misdiagnose. view:clear locally, view:cache last in the pipeline.
Sequencing.
composer why-not resolves with the current PHP constraint.<x-icon name="..." /> absorbing sizing (w-4 h-4, 16px grid — stick to 16 and 32 for crispness, check 20px edges manually), the accessibility contract, shrink-0, and the name indirection. Nothing else ships until this exists.Maintenance. Near-zero steady-state cost and one recurring obligation. The package itself needs nothing — no assets, no config, no runtime. The recurring cost is bump discipline: read the diff, let the CI tests gate it, and treat framework-major compatibility as a runbook line item so it never blocks a Laravel upgrade mid-flight. That is the highest-probability real failure mode, and 1.35.0 was exactly a runbook-item release. Total ownership footprint is one small pinned dependency plus one wrapper file plus one config map — a 1–2 day build task removed from the roadmap, priced as an ongoing maintenance trade.
Support. Single maintainer, bus factor of 1, negligible public adoption, MIT. We should not plan on upstream responsiveness for glyph requests or bug fixes. Two consequences: (a) coverage is fixed upstream — a missing glyph is a design decision resolved with a small local escape hatch of hand-written SVGs inside the wrapper, not a PR to this package and not a fork; (b) the wrapper is our real support contract, because it is the thing we control when the vendor changes or is abandoned. Internal support burden is minimal — the wrapper's prop signature is the only thing a feature team needs to learn.
Scaling. Scales fine along the dimensions that matter here: no runtime cost, no external asset fetch, no per-request network hop, cache-friendly static markup, and it works identically in Livewire components and Blade partials. The one dimension where it does not scale gracefully is page density — inline SVG is verbose, and icon-dense public pages are the wrong shape (a sprite strategy or fragment caching is better). That is a design constraint to hold, not a defect to fix. Sizing discipline also matters at scale: enforce 16/32 via the wrapper so the icon system does not drift into hand-tuned pixel values across a hundred views.
Failure modes.
| Failure | Blast radius | Mitigation |
|---|---|---|
| Renamed/dropped glyph on a version bump | Render-time exception (500) on affected pages | Pin version; name-map render test in CI |
| Typo'd component name in a view | 500 at render, in production | Wrapper + whitelist test; ban raw <x-codicon-*> in views |
| Framework major upgrade blocked | Upgrade stalls | Add compat check to Laravel upgrade runbook |
| Stale compiled views after deploy | "Component not found" surviving a naive cache clear | composer install before view:cache; view:clear locally |
Missing aria-hidden |
Accessibility audit finding across all decorative icons | Bake into wrapper's default branch |
Inherited text-transparent |
Icon silently invisible | Wrapper defaults + documented ancestor rule |
| Icon-dense page payload | Slow responses on large tables | Measure in pilot; reduce icons/row or fragment-cache |
Ramp-up. Effectively zero for a Laravel developer — the syntax is standard Blade. The training investment is not in the package but in the conventions: one short note covering the wrapper API, the 16/32 sizing rule, the decorative-vs-labeled accessibility contract, the "don't use in email" rule, and the ban on raw <x-codicon-*> in views. Budget half a day for the wrapper, config map, and tests; a feature team is productive the same afternoon. The people who need the most context are not developers but design and PM, who need the surface boundary (internal yes, brand no) stated once and owned rather than re-litigated per screen.
How can I help you explore Laravel packages today?