twbs/bootstrap-icons
Official open source SVG icon library for Bootstrap, offering over 2,000 free, MIT-licensed icons. Install via npm (bootstrap-icons) or Composer, then use as embedded HTML, img tags, an SVG sprite, or CSS. Also available in Figma.
Architecture fit
twbs/bootstrap-icons is a content-only distribution package: ~2,000 optimized 16×16 SVGs plus derived artifacts (icon font in woff2/woff, bootstrap-icons.svg sprite, bootstrap-icons.css/.scss). It ships no PHP, no service provider, no config, no autoload entry. It is published to Packagist purely as a file carrier alongside npm. That makes it a near-perfect fit for a Laravel app's presentation layer and a poor fit for any team expecting a framework-integrated API (facade, Blade directives, config-driven icon sets). The correct mental model is "a vendored design asset with a version number," not "a library we integrate."
Architecturally it slots in cleanly at three seams:
vendor/twbs/bootstrap-icons/icons/{name}.svg.public/.It is framework- and CSS-agnostic: it does not require Bootstrap 5 CSS to be present, so it can be dropped into a Tailwind, Livewire, or Inertia app without dragging in the Bootstrap grid.
Integration feasibility High. Four viable paths, ordered by operational cost:
<x-bi name="alarm" /> reads the SVG via file_get_contents(base_path('vendor/twbs/bootstrap-icons/icons/…')). Zero external requests, full CSS currentColor control, per-icon tree-shaking by construction, CSP-friendly.blade-ui-kit/blade-icons with a custom icon set — register a class pointing at the vendor icons/ path; you get <x-icon-bootstrap-alarm />, built-in caching, and a consistent API across multiple icon sets. Best choice if the app already standardizes on blade-icons.bootstrap-icons.svg to public/ and use <svg><use href="/icons.svg#alarm"/></svg>. One cached HTTP request, good for icon-dense UIs, but <use> has styling and shadow-DOM quirks and can't easily hold per-instance titles.<i class="bi bi-alarm"></i>. Fastest to adopt, worst a11y (pseudo-element content, no accessible name), adds a font payload regardless of icon count, and breaks under restrictive font-src CSP.Technical risk
cassette* renamed in v1.9.1, building → buildings in v1.10.0. SemVer here tracks repo changes, not slug stability. A routine composer update can silently blank an icon in production.{!! !!} without an allowlisted name.public/ symlinks or blind asset('vendor/…') assumptions will 404. Anything served directly must be explicitly published or copied at build time.Dependents: 0 is implausible for an official Bootstrap package and almost certainly a Packagist counting artifact; Last release: 2026-10-08 post-dates the newest changelog content (v1.10.5) in the same source set. Both should be treated as scoring-pipeline noise and re-verified against Packagist/npm before pinning. The opportunity score of 47.52 correctly reflects low strategic upside — this is a commodity "buy, don't build" decision whose value is avoided design/labor cost, not differentiation.Key questions
font-src directive?fa-* → bi-* mapping will silently miss glyphs with no equivalent.Stack fit
Excellent for Laravel 9–11 (Vite), Laravel 8 (Mix), Blade, Livewire, and Inertia. PHP version compatibility is a non-issue — composer.json declares no PHP constraint, so it will install alongside any Laravel-supported runtime. It does not conflict with Bootstrap CSS versioning, Tailwind, or any component library. For a Laravel app already using Bootstrap 5 theming, this is the default-choice icon set with zero stylistic friction.
Migration path
UNMAPPED bucket. Do not proceed until that bucket is triaged.<x-icon> / <x-bi>). Every call site goes through it — never raw <i class="bi …"> scattered in views.Compatibility
composer require twbs/bootstrap-icons — installs cleanly, but be aware nothing is registered. composer install --no-dev and --prefer-dist both ship the icons/ and font/ directories, so production builds retain the assets.npm i bootstrap-icons plus import 'bootstrap-icons/font/bootstrap-icons.css' works with Vite 4/5 and Laravel Mix. Vite resolves from node_modules; Composer's vendor/ path needs explicit resolve.alias or a copy step.file_get_contents reads. Serverless/Lambda with vendor zipped into a layer is also fine, but confirm the path is stable across your build stage.~1.11.0 or an exact pin — not ^1. Minor releases rename slugs.Sequencing
| Phase | Work | Exit criteria |
|---|---|---|
| 0. Spike (0.5 d) | Render 3 icons via both Blade-component and font modes in staging | Both render; vendor path confirmed in the real deploy image |
| 1. Contract (1 d) | Icon-name allowlist, single Blade component, a11y rules (aria-hidden decorative / aria-label interactive) |
Lint rule or code review checklist in place |
| 2. Governance (0.5–1 d) | CI test asserting every referenced slug exists in vendor/…/icons/; exact version pin |
Test fails on a simulated rename |
| 3. Migrate (2–4 d) | Traffic-ordered view migration via the abstraction | Legacy icon CSS/font removed from bundle |
| 4. Harden | CSP review, sprite/CDN decision, bundle-size baseline | Page weight delta measured and accepted |
Maintenance Steady-state code maintenance is effectively zero; the package is inert data. The real recurring cost is upgrade review, which is small but non-zero because icon renames ship in minor versions. Budget ~1 hour per version bump plus whatever the CI guard catches. Pin tightly, upgrade deliberately, and treat every bump as a potential silent-blank-icon event rather than a routine security patch.
Support Community-only: GitHub issues, the official docs site (searchable, per-icon HTML snippets in every usage mode), and Bootstrap's blog. MIT, no warranty, no SLA, no vendor to escalate to. The practical escalation path is "copy the SVG we need into our own repo and fork" — which is genuinely viable and worth stating as an accepted mitigation up front. Documentation quality is strong and consumer-facing, which materially reduces internal support load.
Scaling
Static assets scale trivially — serve the sprite or font from CloudFront/Cloudflare with long-lived immutable caching keyed on the version. The one scaling caveat is the inline-SVG path: a naive implementation doing file_get_contents per icon per render will produce thousands of filesystem reads on icon-dense pages. Mitigate with a static per-request memo array, or better, a build step that compiles the used subset into a PHP array warmed by OPcache. Neither is hard, but both must be deliberate.
Failure modes
font-src CSP blocks it — loud visually, silent in logs.public/ publish or Vite copy step is skipped in a deploy variant (classic prod-only regression).vendor/ non-PHP paths — verify the build stage preserves icons/.Ramp-up Low. A mid-level Laravel developer stands up the Blade component and migrates a representative page in under a day; full governance, CI guard, and a mid-size app migration is roughly 3–5 developer-days. The docs shortens onboarding further. The genuinely non-obvious parts — slug churn across minors, the vendor-path/public-asset mismatch, and a11y conventions for icon-only controls — should be captured in a short internal ADR and the component's docblock so they aren't rediscovered per developer.
Metrics to track Distinct icons in use (drives font-vs-sprite decision), page-weight delta attributable to icons, count of unmapped slugs during migration, and a post-upgrade assertion that zero referenced slugs went missing.
How can I help you explore Laravel packages today?