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

Json Laravel Package

iconify/json

Iconify JSON is a Composer package that bundles thousands of open-source icon sets as JSON data, letting PHP projects search, load, and render icons locally without external API calls. It includes metadata, aliases, and SVG path data for flexible icon workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

iconify/json is a data-only Composer package — no PHP classes, no service provider, no autoloaded API. It drops ~150 icon-set JSON files into vendor/iconify/json/json/, one per prefix (mdi.json, heroicons.json, tabler.json, ph.json, lucide.json, …). Your job as the Laravel dev is to write the thin loader. Treat "Dependents: 0" as a warning, not a red flag: nobody wraps this for you.

Install

composer require iconify/json:^2.0

Put it in require only if you resolve icons at request time. If you precompile a subset (recommended, see below), require-dev plus a build step keeps ~150 MB out of the production image.

First place to look

vendor/iconify/json/collections.json        # catalogue: every prefix + license + author + samples
vendor/iconify/json/json/mdi.json           # one set

collections.json is your discovery map — use it to list valid prefixes and check licensing before you commit to a set.

Anatomy of a set file

{
  "prefix": "mdi",
  "info": { "name": "Material Design Icons", "license": { "title": "Apache 2.0", "spdx": "Apache-2.0" } },
  "lastModified": 1725000000,
  "width": 24, "height": 24,
  "icons": {
    "home": { "body": "<path d=\"M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z\"/>" }
  },
  "aliases": {
    "house": { "parent": "home", "hFlip": true }
  }
}

First use case — a single inline SVG in a Blade view, no component yet:

$set  = json_decode(file_get_contents(base_path('vendor/iconify/json/json/mdi.json')), true, flags: JSON_THROW_ON_ERROR);
$icon = $set['icons']['home'];
$w = $icon['width']  ?? $set['width']  ?? 24;
$h = $icon['height'] ?? $set['height'] ?? 24;
<svg viewBox="0 0 {{ $w }} {{ $h }}" fill="currentColor" aria-hidden="true">{!! $icon['body'] !!}</svg>

That's the whole contract. Everything else is caching, aliasing, and ergonomics.

Implementation Patterns

1. A memoizing resolver service (singleton)

Resolve prefix:name, walk aliases, and derive dimensions in one place. Bind it as a singleton so each set file is decoded at most once per request.

namespace App\Support;

use RuntimeException;

class Iconify
{
    private array $sets = [];

    public function resolve(string $name): ?array
    {
        [$prefix, $icon] = array_pad(explode(':', $name, 2), 2, null);
        if (!$prefix || !$icon) {
            throw new RuntimeException("Icon name must be 'prefix:name', got [{$name}]");
        }

        $set = $this->set($prefix);
        if (!$set) {
            return null;
        }

        $data = $set['icons'][$icon] ?? null;
        $transform = [];

        // Aliases: parent + rotate/hFlip/vFlip
        $seen = [];
        while ($data && isset($data['parent'])) {
            if (isset($seen[$data['parent']])) break;          // cycle guard
            $seen[$data['parent']] = true;
            foreach (['rotate', 'hFlip', 'vFlip'] as $k) {
                if (!empty($data[$k])) $transform[$k] = $data[$k];
            }
            $data = $set['icons'][$data['parent']] ?? $set['aliases'][$data['parent']] ?? null;
        }

        if (!$data || !empty($data['hidden'])) {
            return null;
        }

        return [
            'body'   => $data['body'],
            'width'  => $data['width']  ?? $set['width']  ?? 24,
            'height' => $data['height'] ?? $set['height'] ?? 24,
            'transform' => $this->cssTransform($transform),
        ];
    }

    private function set(string $prefix): ?array
    {
        return $this->sets[$prefix] ??= (function () use ($prefix) {
            if (!preg_match('/^[a-z0-9-]+$/', $prefix)) return null;
            $path = base_path("vendor/iconify/json/json/{$prefix}.json");
            return is_file($path)
                ? json_decode(file_get_contents($path), true, flags: JSON_THROW_ON_ERROR)
                : null;
        })();
    }

    private function cssTransform(array $t): ?string
    {
        $parts = [];
        if (!empty($t['rotate'])) $parts[] = 'rotate(' . (int) $t['rotate'] . 'deg)';
        $sx = !empty($t['hFlip']) ? -1 : 1;
        $sy = !empty($t['vFlip']) ? -1 : 1;
        if ($sx !== 1 || $sy !== 1) $parts[] = "scale({$sx}, {$sy})";
        return $parts ? implode(' ', $parts) : null;
    }
}
// AppServiceProvider::register()
$this->app->singleton(Iconify::class);

2. A Blade component, not raw includes

// app/View/Components/Icon.php
class Icon extends Component
{
    public function __construct(public string $name, public ?string $size = null) {}

    public function render() { return view('components.icon'); }
}
{{-- resources/views/components/icon.blade.php --}}
@php($icon = app(\App\Support\Iconify::class)->resolve($name))
@if($icon)
<svg {{ $attributes->merge(['class' => $size ? "w-{$size} h-{$size}" : 'w-5 h-5']) }}
     viewBox="0 0 {{ $icon['width'] }} {{ $icon['height'] }}"
     fill="currentColor" aria-hidden="true">
    @if($icon['transform'])
        <g transform="{{ $icon['transform'] }}">{!! $icon['body'] !!}</g>
    @else
        {!! $icon['body'] !!}
    @endif
</svg>
@else
    {{-- fail loudly in dev, silently in prod --}}
    @if(app()->hasDebugModeEnabled()) {{-- unknown icon: {{ $name }} --}} @endif
@endif

Usage: <x-icon name="mdi:home" size="6" class="text-blue-600" />. currentColor + Tailwind size classes gives you theming for free.

3. The production pattern: compile a subset at build time

Decoding mdi.json (~5–8 MB, 7 000+ icons) per request is the #1 mistake. Scan your templates and dump a single PHP array — opcache-friendly, no json_decode at runtime.

// app/Console/Commands/CompileIcons.php — php artisan icons:compile
$used = collect(File::allFiles(resource_path('views')))
    ->flatMap(fn ($f) => preg_match_all('/(?:mdi|heroicons|ph|tabler|lucide):[a-z0-9-]+/', $f->getContents(), $m) ? $m[0] : [])
    ->merge(config('icons.extra', []))
    ->unique();

$resolver = app(Iconify::class);
$map = $used->mapWithKeys(fn ($n) => [$n => $resolver->resolve($n)])->filter()->all();

File::put(app_path('Support/compiled-icons.php'), '<?php return ' . var_export($map, true) . ';');

Bind Iconify to read the compiled map first and fall back to file reads only when app()->isLocal(). Wire it into composer.json scripts or your Vite/CI step.

4. Sprite mode for icon-heavy UIs

If a page renders 100+ icons, inline SVGs bloat the DOM. Build a <symbol> sheet from the compiled map at build time and emit <svg><use href="#mdi-home"/></svg> at runtime. One request, shared <defs>, cache-friendly.

5. Bridges and interop

  • Blade Icons: community adapters exist that register Iconify prefixes as Blade Icons sets (search Packagist for the current blade-iconify package name before committing — it's moved around).
  • Tailwind / Filament: Filament already uses Blade Icons; registering one or two Iconify prefixes gives you thousands of icons in icon() calls for free.
  • Inertia + Vue/React: if your frontend uses @iconify/vue, the same JSON is the data source. Install via npm to avoid duplicating the payload across vendor/ and node_modules/ in your image.

6. Config-driven set allowlist

Expose only the prefixes you use (config/icons.php: ['allowed' => ['mdi','heroicons']]) and whitelist icon names in a form request when a name comes from user input. Never interpolate an arbitrary prefix into a file path.

Gotchas and Tips

Size and CI. The package unpacks to well over a hundred megabytes. On composer install that's slow, and in Docker it bloats layers. Keep it in require-dev, run composer install --no-dev in the runtime stage, and copy the compiled icon map forward. If you must ship it, strip unused sets in a post-install script.

No PHP API. There is no Iconify::get(). Anything you see in docs is JS (@iconify/json-tools, @iconify/tools). You are writing the resolver — budget an hour, not five minutes.

Licensing is per set, and it varies. info.license (and collections.json) carries SPDX ids per collection; some sets are GPL/CC-BY and require attribution. If you're shipping a commercial product, build a small allowlist of Apache/MIT/OFL-safe prefixes and reject the rest in your resolver. This is the most common legal surprise with this package.

ID collisions when inlining. A few sets (logos, gradients, masks) emit <defs>, <linearGradient id="a">, or <mask id="b"> inside body. Inline two of them and the browser binds both use/fill references to the first id. Fix: rewrite id="X" → id="{prefix}-{name}-X" inside the body when compiling, and update matching url(#X)/href="#X" references. Only bite when you hit it, but know where to look.

Aliases are not just pointers. aliases entries carry parent, rotate, hFlip, vFlip, and sometimes have their own body. Miss the transforms and your flipped arrows point the wrong way. Also, hidden: true marks deprecated icons — filter them out rather than rendering dead glyphs.

Dimensions are not always square, not always 24. Some sets default to 16, some to 24, some to 48 and 512 (logos). Always fall back icon → set root → 24, and always build the viewBox from the resolved pair, never hardcode 0 0 24 24.

Memory. json_decode of a large set inflates to roughly 8–10× file size as a PHP array. Two large sets resident in one request can push you past a 128 MB memory_limit. Memoize per-request (as above), and cache the compiled map — not the raw sets — in Redis.

Naming is exact. mdi:home ≠ mdi:Home ≠ mdi:home-outline. Names are lowercase and hyphenated; validate with /^[a-z0-9]+(-[a-z0-9]+)*$/ per icon segment. A typo silently renders nothing, which is why the dev-mode comment in the component matters.

lastModified moves. Package updates can change a body's path data or drop an icon. If pixel-stability matters (design system, snapshot tests), pin the exact iconify/json version and commit the compiled map — it becomes your source of truth, and upgrades become reviewable diffs.

Extension points worth building once: an icons:compile command, an icons:list --prefix=mdi --search=arrow command for discovery (grep the keys), an icons:validate check in CI that fails on unresolved prefix:name in templates, and a icons:prune that deletes non-allowlisted JSON before the production build. Those four commands turn this data dump into a genuine asset.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package