Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blade Icon Picker Laravel Package

nickperkins/blade-icon-picker

A standalone icon picker Blade component for Livewire forms that works with any blade-icons pack, featuring search, lazy rendering, keyboard navigation, and responsive styling with no Tailwind dependency.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a Blade component wrapping an Alpine.js island, not a Livewire component. That single decision determines where it fits. On render, the server enumerates registered blade-icons sets and hands the browser a catalog; the browser owns search, filtering, lazy chunking, and keyboard navigation, and the only server round-trip on selection is $wire.set(). For a Laravel 10–13 + Livewire 3/4 + blade-icons application, this is a clean, low-coupling fit that avoids per-keystroke wire:model.live search cost. It is a poor fit for Livewire 2, Inertia/Vue/React forms, or any UI where Alpine is not already present — the coupling becomes dead weight.

The strongest architectural property is interoperability of the persisted value. The stored string (e.g. heroicon-o-home) follows the blade-icons ID convention consumed by @svg(), svg(), and Filament, so the data written to the database remains valid if the picker UI is later swapped or removed. That is the main reason this is a low-regret adoption and the argument to lead with in a design review.

Integration feasibility. Requirements are mainstream and low-friction: PHP 8.2+, Laravel 10–13, Livewire 3/4, blade-icons 1.0+. Install is composer require, one tagged asset publish, and two manual <link>/<script> tags — no service-provider configuration, migrations, queues, or external services. Nothing here needs platform change approval beyond a routine dependency review.

Technical risk, ranked:

  1. Vendor and bus-factor risk. Zero stars, zero dependents, single maintainer, no observable third-party usage. There is no community buffer to surface bugs before we do. MIT licensing and a small surface area make vendoring or forking credible, which caps the downside — but assume we own it.
  2. Documentation drift that will generate support tickets. The README says dark mode does not auto-detect prefers-color-scheme and then says it is supported automatically; theming examples reference .icon-picker-root while the dark-mode section references .ip-root; the README lists Laravel 10–12 / Livewire 3 while the v1.0.0 release notes list Laravel 10–13 / Livewire 3 or 4; the description contains a "Lightwire 3" typo. v1.1.0 shipped AJAX-based icon loading with set/variant filtering that is not documented in the README at all — the docs lag the code, which is the highest-signal maturity indicator here.
  3. Payload and render cost, now partially mitigated but unmeasured. Pre-v1.1.0 the entire catalog was serialized into every hosting page (Heroicons v2 ≈ 1,200 glyphs, plausibly hundreds of KB of inline SVG plus per-request SVG rendering). The AJAX path should cut first-paint cost substantially, but how the endpoint is registered, whether it is authenticated, and whether it is cacheable are all undocumented. Treat the performance story as unverified until measured.
  4. Dual-binding footgun. wire:model alone does not seed the initial value; :value="$icon" is mandatory. Developers will ship a picker that silently fails to redisplay a saved icon. Validation and error display are entirely the host app's responsibility.
  5. Unverified accessibility. Arrow keys, Enter, and Escape are claimed; ARIA combobox/listbox semantics, focus management, active-descendant announcement, and screen-reader behavior are neither documented nor evidenced. Assume unverified.
  6. Rigid configuration surface. Chunk size is a hardcoded constant (30). No documented config for icon-set allow-listing, so a project with Heroicons + Font Awesome + a custom pack embeds or fetches all of them.
  7. CSP and Alpine coexistence. Inline SVG insertion (x-html/innerHTML) and Alpine inline expressions interact with strict CSPs, and a second Alpine instance on the page is a known conflict class.

Key questions for engineering and the maintainer

  1. What is the measured payload and render-time delta on a representative page, for our packs, under v1.1.0's AJAX mode versus the full-inline mode?
  2. How is the AJAX endpoint registered — auto-discovered route, named route, or config-gated? Is it authenticated, rate-limited, and cacheable per deployment?
  3. Can the catalog be cached per-pack or pre-generated as a static asset, and is that on the roadmap?
  4. What happens when :value holds a stale or unregistered icon ID (renamed/removed pack)? Silent blank, exception, or graceful fallback?
  5. With two pickers on one page, is the catalog fetched or serialized twice?
  6. Is there a config file for chunk size, pack allow-listing, or label formatting, or is the API effectively fixed?
  7. Accessibility conformance: any combobox/listbox ARIA semantics, and has it been tested with VoiceOver/NVDA?
  8. Alpine version floor, and does it conflict with an app-provided Alpine instance?
  9. Does inline SVG use x-html/innerHTML, and is that compatible with our CSP (no unsafe-inline)?
  10. What are the maintainer's support intent and release cadence for the next 12 months?

Integration Approach

Stack fit. Adopt only where the target is Laravel 10–13 + Livewire 3/4 and blade-icons is already present or an easy yes. Tailwind is not required — the standalone CSS is a genuine advantage for admin panels living outside the main design system. If the form layer is Vue/React/Inertia or Livewire 2, stop.

Migration path. Low risk in both directions because the stored value is blade-icons-native:

  • From a plain text input, a <select> of icon names, or a hand-rolled grid: the column already holds (or can be backfilled to) a blade-icons ID, so no schema change is required — only the form field is swapped.
  • From lukas-frey/filament-icon-picker: same underlying ID convention, so the value format survives; only the UI dependency changes.
  • Away from it later: reverting to a text field or a different picker preserves all existing data. Worst case is a UI regression, not a data migration.

Compatibility checks before committing. Confirm PHP/Laravel/Livewire versions in composer.json against ours; confirm an installed blade-icons pack (add blade-ui-kit/blade-heroicons if not); confirm the deploy pipeline permits and commits published assets with cache-busting; confirm CSP allows inline SVG and Alpine inline expressions; resolve the dark-mode contract (ip-dark class vs [data-theme] attribute) against our actual theme mechanism in a spike rather than from the README.

Sequencing.

  1. Spike (½–1 day, one dev). Install on a scratch branch, publish assets, wire one picker into an existing Livewire form. Capture payload size and server render time in both the AJAX and full-inline modes, Lighthouse impact, keyboard and screen-reader behavior, dark-mode behavior under our real theme toggle, and whether validation errors display correctly.
  2. Decision gate. Proceed if payload and render cost are acceptable or a catalog-caching workaround is cheap; otherwise defer and revisit in 1–2 quarters.
  3. Standardize. Wrap the component in an internal Blade partial (e.g. <x-app.icon-field>) that enforces the wire:model + :value pairing, renders the error slot, and binds the theme class. No product developer calls the vendor tag directly. This is the single highest-value integration step and the one that keeps support cost flat.
  4. Pilot. One low-traffic admin screen for a sprint, with page weight and error logs instrumented.
  5. Rollout. Remaining forms in batches; add a PR-checklist rule for the dual-binding pattern.
  6. Contingency. Pin the exact version, commit the published assets, and record a fork-ready note — the package is small enough for one developer to own a fork if upstream stalls.

Operational Impact

Maintenance. Assume we own this, not the upstream author. Pin a version, commit the published dist assets so deploys do not depend on re-publishing, and document a fork decision point. Budget a recurring allowance for dependency bumps tied to Laravel and Livewire major releases. The internal wrapper partial is what absorbs version churn — upgrade the wrapper, not N call sites.

Support. No SLA, no support policy, no dependents, no issue-tracker history to lean on. First-line support is our own team. Two documentation defects (dark mode, selector naming) will generate recurring questions from front-end developers who copy examples without testing; write a short internal usage note in the wrapper's README that supersedes upstream docs, and link it in code review guidance.

Scaling. Two axes matter. Breadth: cost scales with the number of forms using the picker until the wrapper exists; after that, marginally. Page weight: cost scales with the number of icon packs installed and the number of pickers per page. Enforce pack allow-listing at the wrapper level (and confirm whether v1.1.0's set/variant filtering gives us a lever), and avoid placing a picker on high-traffic public pages — admin and configuration surfaces only.

Failure modes to plan for.

  • Assets not published or not committed → 404 on CSS/JS after deploy; component degrades to an unstyled, non-interactive list. Mitigation: commit dist files, assert presence in a post-deploy smoke check.
  • Missing or renamed icon pack → the component renders a developer-facing "install Heroicons" message in production. Mitigation: treat the message as an alert-worthy log signal, and validate stored IDs against the live catalog on save.
  • Dual-binding omission → saved icon fails to redisplay; silent, user-visible, hard to trace. Mitigation: wrapper partial plus PR checklist.
  • Stale icon ID → previously stored value no longer resolves; behavior undocumented.
  • Alpine instance conflict or wire:navigate re-init → picker initializes once and dies after navigation. Mitigation: explicitly test SPA-style navigation in the spike.
  • CSP violation → component renders but icons do not. Mitigation: verify against the production CSP header, not the dev server's.
  • Performance regression on cached pages → catalog serialization inflates cached HTML. Mitigation: prefer the AJAX mode, and monitor response size on hosting pages.

Ramp-up. Minimal. A mid-level Laravel developer can be productive in under an hour given working examples; deep familiarity (AJAX endpoint, catalog discovery, theme contract) takes roughly half a day. The wrapper partial means most developers never touch the vendor API. Documentation debt — not code complexity — is the real ramp-up cost, so the internal note is doing more load-bearing work than usual for a package this small.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode