Skip to content
Brok UI

Loading…

No results

Icon

Open source Core

Renders a centrally maintained icon by name, with semantic currentColor styling, fixed size presets, and decorative or labelled accessibility modes; <x-ui.icon.tile> sits a named icon or an inline SVG in a tinted tile.

Version
v1.11.0
Stability
stable
License
MIT
Related
Button

Preview

Size
previews.components.icon.default.blade.php Blade
{{-- One glyph: the playground's size control resizes it. See the gallery for every name. --}}
<x-ui.icon name="search" size="lg" label="{{ __('Search') }}" />
Xs Current
Sm Current
Md Current
Lg Current
Xl Current

Installation

terminal
php artisan ui:add icon

Registry contract

php artisan ui:add icon writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.

  • blade resources/views/components/ui/icon.blade.php
  • blade resources/views/components/ui/icon/tile.blade.php
Registry dependencies
None — installs on its own.
Packages
composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.

icon.md
# Brok UI: Icon (`icon`)

Renders a centrally maintained icon by name, with semantic currentColor styling, fixed size presets, and decorative or labelled accessibility modes; <x-ui.icon.tile> sits a named icon or an inline SVG in a tinted tile.

Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.

## Install

```bash
php artisan ui:add icon
```

## Usage

```blade
{{-- One glyph: the playground's size control resizes it. See the gallery for every name. --}}
<x-ui.icon name="search" size="lg" label="{{ __('Search') }}" />
```

## Props

- `name` (archive|arrow-down|arrow-left-right|arrow-up|bar-chart|bell|book-open|bot|building|calendar|check|chevron-down|chevron-end|chevron-start|chevron-up|circle|clock|close|command|compass|copy|credit-card|download|external-link|file-text|film|filter|folder|help-circle|history|image|inbox|info|keyboard|languages|link|log-out|menu|minus|monitor|moon|more-horizontal|paperclip|pencil|play|plug|plus|receipt|redo|search|settings|shield|sliders|star|star-filled|sun|tag|trash|undo|user|users|video|wallet|warning|zoom-in|zoom-out, default `required`) — Centrally maintained icon name.
- `size` (xs|sm|md|lg|xl, default `md`) — Fixed icon size preset.
- `label` (string|null, default `null`) — Accessible name when the icon carries meaning; omit for decorative icons.
- `strokeWidth` (1|1.5|2|2.5, default `2`) — Allowlisted SVG stroke width.
- `tone` (string, default `primary`) — Declared by @props in the registry Blade source.

## Use when

- Use to summarize, sequence, or present data so users can scan it quickly.
- A standard interface glyph must stay consistent across applications.
- An app shell or sidebar needs navigation glyphs (compass, users, folder, calendar, clock, credit-card, receipt, file-text, settings, inbox, book-open, bar-chart, wallet, plug, log-out) instead of hand-drawn SVGs.
- An account, settings or workspace menu needs item glyphs (user, building, shield, sliders, arrow-left-right, sun, moon, languages, help-circle, history) placed first inside a dropdown item.
- A favourite, pin or rating toggle needs an outline star for off and the same star filled (star-filled) for on, swapped with the pressed state.
- A notifications trigger needs a bell, a collapse or move-up control needs chevron-up, or a sort or reorder control needs arrow-up and arrow-down.
- A media or source row needs a kind glyph (link, image, video, film, bot), an outbound link needs external-link, a media control needs play, zoom-in or zoom-out, or a status needs a plain circle.

## Avoid when

- Do not add display-only ornament when the user needs actionable structure or exact comparison instead.
- A product-specific illustration or brand mark is required.

## Anti-patterns

- Adding display ornament without informational value

## Rules

- Use the `<brok:icon>` tag (or `<x-ui.icon>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.

## Links

- Docs: https://brokui.dev/docs/components/icon
- Registry JSON (files, props, contract): https://brokui.dev/r/open/icon.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

Examples

actions.blade.php Blade
{{-- The row-action set: the overflow trigger, the commands it usually holds (edit, copy, archive, delete, export, filter, label, keyboard shortcuts), and a pager whose chevrons follow the reading direction. --}}
@php
    $actions = [
        'more-horizontal' => __('More actions'),
        'pencil' => __('Edit'),
        'copy' => __('Copy link'),
        'archive' => __('Archive'),
        'trash' => __('Delete'),
        'download' => __('Export CSV'),
        'filter' => __('Filter'),
        'tag' => __('Add label'),
        'keyboard' => __('Keyboard shortcuts'),
    ];
@endphp
<div class="flex w-full max-w-md flex-col gap-6 text-sm text-foreground">
    <ul class="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2">
        @foreach ($actions as $name => $action)
            <li class="flex items-center gap-2">
                <x-ui.icon :name="$name" size="sm" class="text-muted-foreground" />
                <span>{{ $action }}</span>
            </li>
        @endforeach
    </ul>
    <div class="flex items-center gap-2">
        <span class="flex items-center gap-2">
            <x-ui.icon name="chevron-start" size="sm" class="text-muted-foreground" />
            {{ __('Previous') }}
        </span>
        <span class="flex items-center gap-2 ms-auto">
            {{ __('Next') }}
            <x-ui.icon name="chevron-end" size="sm" class="text-muted-foreground" />
        </span>
    </div>
</div>
controls.blade.php Blade
{{-- Control glyphs: a notifications button, a collapse toggle and a sort control, each named for screen readers. --}}
<div class="flex flex-wrap items-center gap-4 text-sm text-foreground">
    <x-ui.button size="icon" variant="ghost" :aria-label="__('Notifications')">
        <x-ui.icon name="bell" />
    </x-ui.button>
    <x-ui.button size="icon" variant="ghost" :aria-label="__('Collapse section')" aria-expanded="true">
        <x-ui.icon name="chevron-up" />
    </x-ui.button>
    <div class="flex items-center gap-2">
        <x-ui.button size="icon" variant="ghost" :aria-label="__('Move up')">
            <x-ui.icon name="arrow-up" />
        </x-ui.button>
        <x-ui.button size="icon" variant="ghost" :aria-label="__('Move down')">
            <x-ui.icon name="arrow-down" />
        </x-ui.button>
    </div>
</div>
favorite.blade.php Blade
{{-- A favourite toggle: the outline star when off, the same star filled when on, swapped with aria-pressed. --}}
<div class="flex flex-wrap items-center gap-6 text-sm text-foreground">
    <div class="flex items-center gap-2">
        <x-ui.icon name="star" size="sm" class="text-muted-foreground" />
        <span>{{ __('Not a favorite') }}</span>
    </div>
    <div class="flex items-center gap-2">
        <x-ui.icon name="star-filled" size="sm" />
        <span>{{ __('Favorite') }}</span>
    </div>
    <div x-data="{ favorite: false }">
        <x-ui.button
            size="icon"
            variant="ghost"
            :aria-label="__('Favorite')"
            x-on:click="favorite = !favorite"
            x-bind:aria-pressed="favorite ? 'true' : 'false'"
            aria-pressed="false"
        >
            <x-ui.icon name="star" x-show="!favorite" />
            <x-ui.icon name="star-filled" x-show="favorite" x-cloak />
        </x-ui.button>
    </div>
</div>
media.blade.php Blade
{{-- Media and source glyphs: a kind glyph per source row, an outbound link that mirrors in RTL, and media controls whose play glyph keeps its direction. --}}
@php
    $kinds = [
        'link' => __('Web page'),
        'image' => __('Screenshot'),
        'video' => __('Screen recording'),
        'film' => __('Film clip'),
        'bot' => __('Assistant note'),
    ];
@endphp
<div class="flex w-full max-w-md flex-col gap-6 text-sm text-foreground">
    <ul class="flex flex-col gap-4">
        @foreach ($kinds as $name => $kind)
            <li class="flex items-center gap-2">
                <x-ui.icon :name="$name" size="sm" class="text-muted-foreground" />
                <span class="min-w-0 flex-1 truncate">{{ $kind }}</span>
                <x-ui.icon name="circle" size="xs" class="text-success" :label="__('Ready')" />
            </li>
        @endforeach
    </ul>
    <div class="flex flex-wrap items-center gap-2">
        <x-ui.button size="icon" variant="ghost" :aria-label="__('Play')">
            <x-ui.icon name="play" />
        </x-ui.button>
        <x-ui.button size="icon" variant="ghost" :aria-label="__('Zoom in')">
            <x-ui.icon name="zoom-in" />
        </x-ui.button>
        <x-ui.button size="icon" variant="ghost" :aria-label="__('Zoom out')">
            <x-ui.icon name="zoom-out" />
        </x-ui.button>
        <a href="#" class="ms-auto inline-flex items-center gap-2 rounded-sm text-foreground underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-[length:var(--ring-width)] focus-visible:ring-ring">
            {{ __('Open source page') }}
            <x-ui.icon name="external-link" size="sm" class="text-muted-foreground" />
        </a>
    </div>
</div>
menus.blade.php Blade
{{-- The menu set: account, workspace and preference rows, each glyph beside the action it names. --}}
@php
    $actions = [
        'user' => __('Profile'),
        'building' => __('Workspace'),
        'arrow-left-right' => __('Switch account'),
        'shield' => __('Security'),
        'sliders' => __('Preferences'),
        'languages' => __('Language'),
        'sun' => __('Light theme'),
        'moon' => __('Dark theme'),
        'history' => __('Audit log'),
        'help-circle' => __('Help'),
    ];
@endphp
<ul class="grid w-full max-w-md grid-cols-1 gap-x-6 gap-y-4 text-sm text-foreground sm:grid-cols-2">
    @foreach ($actions as $name => $action)
        <li class="flex items-center gap-2">
            <x-ui.icon :name="$name" size="sm" class="text-muted-foreground" />
            <span>{{ $action }}</span>
        </li>
    @endforeach
</ul>
navigation.blade.php Blade
{{-- The navigation set in an app shell: each glyph beside the area it names. --}}
@php
    $areas = [
        'compass' => __('My focus'),
        'users' => __('Clients'),
        'folder' => __('Projects'),
        'calendar' => __('Calendar'),
        'clock' => __('Time'),
        'credit-card' => __('Billing'),
        'receipt' => __('Invoices'),
        'file-text' => __('Pages'),
        'inbox' => __('Inbox'),
        'book-open' => __('SOPs'),
        'bar-chart' => __('Reports'),
        'wallet' => __('Finance'),
        'plug' => __('Integrations'),
        'settings' => __('Settings'),
        'log-out' => __('Sign out'),
    ];
@endphp
<ul class="grid w-full max-w-md grid-cols-1 gap-x-6 gap-y-4 text-sm text-foreground sm:grid-cols-2">
    @foreach ($areas as $name => $area)
        <li class="flex items-center gap-2">
            <x-ui.icon :name="$name" size="sm" class="text-muted-foreground" />
            <span>{{ $area }}</span>
        </li>
    @endforeach
</ul>
tile.blade.php Blade
<div class="flex flex-wrap items-center gap-4">
    @foreach (['primary', 'solid', 'muted', 'outline', 'success', 'warning', 'destructive', 'info'] as $tone)
        <x-ui.icon.tile name="check" :tone="$tone" :label="__(ucfirst($tone))" />
    @endforeach
    <x-ui.icon.tile size="sm">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2 2 7l10 5 10-5-10-5Z" /><path d="M2 17l10 5 10-5" /><path d="M2 12l10 5 10-5" /></svg>
    </x-ui.icon.tile>
    <x-ui.icon.tile size="lg">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2 2 7l10 5 10-5-10-5Z" /><path d="M2 17l10 5 10-5" /><path d="M2 12l10 5 10-5" /></svg>
    </x-ui.icon.tile>
</div>

API

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
Prop Type Default Description
name archive | arrow-down | arrow-left-right | arrow-up | bar-chart | bell | book-open | bot | building | calendar | check | chevron-down | chevron-end | chevron-start | chevron-up | circle | clock | close | command | compass | copy | credit-card | download | external-link | file-text | film | filter | folder | help-circle | history | image | inbox | info | keyboard | languages | link | log-out | menu | minus | monitor | moon | more-horizontal | paperclip | pencil | play | plug | plus | receipt | redo | search | settings | shield | sliders | star | star-filled | sun | tag | trash | undo | user | users | video | wallet | warning | zoom-in | zoom-out required Centrally maintained icon name.
size xs | sm | md | lg | xl md Fixed icon size preset.
label string | null null Accessible name when the icon carries meaning; omit for decorative icons.
strokeWidth 1 | 1.5 | 2 | 2.5 2 Allowlisted SVG stroke width.
tone string primary Declared by @props in the registry Blade source.

Slots

  • default — `<x-ui.icon.tile>` only: an inline `<svg>` drawn inside the tile when no `name` is given.
  • x-ui.icon.tile — Installed subcomponent from the registry item.

Data slots

Stable hooks for CSS overrides and browser tests.

icon icon-tile

Behavior

  • Unknown names fail with a clear exception instead of rendering unsafe markup.
  • Directional glyphs (chevron-start, chevron-end, log-out, external-link) mirror under dir="rtl": chevron-start points to the inline start and chevron-end to the inline end in both directions; every other glyph keeps its drawing.
  • play is a media control and does not mirror: playback direction does not follow the reading direction.
  • The set is drawn in this repository (icons/icons.json `source`): 24px grid, round caps and joins, 2px stroke, MIT open core. npm run icons:sync regenerates the Blade map and IconRegistry from that file.
  • star-filled is the one state glyph: the star outline with a currentColor fill, the same size and stroke as star, so swapping the two never shifts the layout.
  • Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.

Guidance

Scannable data display

Present data for rapid scanning.

Use when

  • Use to summarize, sequence, or present data so users can scan it quickly.
  • A standard interface glyph must stay consistent across applications.
  • An app shell or sidebar needs navigation glyphs (compass, users, folder, calendar, clock, credit-card, receipt, file-text, settings, inbox, book-open, bar-chart, wallet, plug, log-out) instead of hand-drawn SVGs.
  • An account, settings or workspace menu needs item glyphs (user, building, shield, sliders, arrow-left-right, sun, moon, languages, help-circle, history) placed first inside a dropdown item.
  • A favourite, pin or rating toggle needs an outline star for off and the same star filled (star-filled) for on, swapped with the pressed state.
  • A notifications trigger needs a bell, a collapse or move-up control needs chevron-up, or a sort or reorder control needs arrow-up and arrow-down.
  • A media or source row needs a kind glyph (link, image, video, film, bot), an outbound link needs external-link, a media control needs play, zoom-in or zoom-out, or a status needs a plain circle.

Avoid when

  • Do not add display-only ornament when the user needs actionable structure or exact comparison instead.
  • A product-specific illustration or brand mark is required.

Use instead

  • Table for exact comparison
  • Plain text for a single value

Anti-patterns

  • Adding display ornament without informational value
Anatomy
svg root trusted copied glyph body icon-tile
Theming hooks
currentColor icon-tile

Accessibility

WCAG 2.2 AA Keyboard focus-visible RTL-ready Localized labels Dark mode
Keyboard
No component-owned keyboard interaction; native element behavior applies.
Focus
none
  • Decorative icons are hidden from assistive technology. Meaningful standalone icons require label.
  • Semantic HTML and a stable data-slot attribute for styling and scripting hooks.
  • Focus-visible rings use the ring token, so keyboard focus is always visible.
  • Disabled and invalid states are conveyed to assistive tech, not by color alone.
  • Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
  • Labels go through __() and layout uses logical properties (ms-*, text-start), so it mirrors under dir="rtl" — flip the preview to RTL to confirm.
  • Dark mode uses the same semantic tokens under the dark class; high contrast follows forced-color system tokens.

Livewire

Safe

Livewire can update this component through forwarded wire:* attributes.

Validation

Validation support: allowlisted-name. Keep the error message connected with aria-describedby.

livewire-form.blade.php Blade
<form wire:submit="save" class="space-y-2">
    <brok:icon
        wire:model="value"
        :aria-invalid="$errors->has('value') ? 'true' : 'false'"
        aria-describedby="value-error"
    />

    @error('value')
        <p id="value-error" role="alert">{{ $message }}</p>
    @enderror

    <brok:button type="submit" wire:loading.attr="disabled">
        <span wire:loading.remove>Save</span>
        <span wire:loading>Saving…</span>
    </brok:button>
</form>

Source

The exact, editable files ui:add writes into your app. Previews render this same code; there are no preview-only components.

resources/views/components/ui/icon.blade.php Blade
@props([
    'name',
    'size' => 'md',
    'label' => null,
    'strokeWidth' => 2,
])

@php
    // Generated by scripts/generate-icons.mjs from icons/icons.json.
    $styles = require base_path(config('ui.component_path', 'resources/views/components/ui').'/_styles.php');
    $sizeClass = $styles['icon']['sizes'][$size] ?? $styles['icon']['sizes']['md'];
    $icons = [
        'archive' => '<rect x="3" y="4" width="18" height="4" rx="1" /><path d="M5 8v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8M10 12h4" />',
        'arrow-down' => '<path d="M12 5v14M19 12l-7 7-7-7" />',
        'arrow-left-right' => '<path d="M4 8h16M16 4l4 4-4 4" /><path d="M20 16H4M8 12l-4 4 4 4" />',
        'arrow-up' => '<path d="M12 19V5M5 12l7-7 7 7" />',
        'bar-chart' => '<path d="M4 21h16M7 17v-5M12 17V5M17 17V9" />',
        'bell' => '<path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9Z" /><path d="M10 21a2 2 0 0 0 4 0" />',
        'book-open' => '<path d="M3 5h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5v13h-6a3 3 0 0 1-3 3 3 3 0 0 1-3-3H3Z" /><path d="M12 9v12" />',
        'bot' => '<rect x="4" y="8" width="16" height="12" rx="2" /><path d="M12 8V4M10 4h4M2 13v3M22 13v3M9 13v2M15 13v2" />',
        'building' => '<path d="M4 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v16" /><path d="M16 9h2a2 2 0 0 1 2 2v10" /><path d="M2 21h20M8 7h4M8 11h4M8 15h4" />',
        'calendar' => '<rect x="3" y="5" width="18" height="16" rx="2" /><path d="M3 10h18M8 3v4M16 3v4" />',
        'check' => '<path d="m5 12 4 4L19 6" />',
        'chevron-down' => '<path d="m6 9 6 6 6-6" />',
        'chevron-end' => '<path d="m9 18 6-6-6-6" />',
        'chevron-start' => '<path d="m15 18-6-6 6-6" />',
        'chevron-up' => '<path d="m6 15 6-6 6 6" />',
        'circle' => '<circle cx="12" cy="12" r="9" />',
        'clock' => '<circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" />',
        'close' => '<path d="M18 6 6 18M6 6l12 12" />',
        'command' => '<path d="M9 6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3z" />',
        'compass' => '<circle cx="12" cy="12" r="9" /><path d="m15.5 8.5-2 5-5 2 2-5Z" />',
        'copy' => '<rect x="8" y="8" width="13" height="13" rx="2" /><path d="M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3" />',
        'credit-card' => '<rect x="2" y="5" width="20" height="14" rx="2" /><path d="M2 10h20M6 15h4" />',
        'download' => '<path d="M12 3v12M7 10l5 5 5-5" /><path d="M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4" />',
        'external-link' => '<path d="M14 4h6v6M20 4l-9 9" /><path d="M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4" />',
        'file-text' => '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8Z" /><path d="M14 3v5h5M9 13h6M9 17h6" />',
        'film' => '<rect x="3" y="3" width="18" height="18" rx="2" /><path d="M7 3v18M17 3v18M3 8h4M3 12h18M3 16h4M17 8h4M17 16h4" />',
        'filter' => '<path d="M3 4h18l-7 8.5V19l-4 2v-8.5Z" />',
        'folder' => '<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z" />',
        'help-circle' => '<circle cx="12" cy="12" r="9" /><path d="M9.5 9.5a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.6v.6M12 17h.01" />',
        'history' => '<path d="M3 12a9 9 0 1 0 2.64-6.36L3 8.3" /><path d="M3 4v4.3h4.3" /><path d="M12 7v5l3 2" />',
        'image' => '<rect x="3" y="3" width="18" height="18" rx="2" /><circle cx="9" cy="9" r="2" /><path d="m21 15-4.5-4.5L5 21" />',
        'inbox' => '<path d="M5.5 5h13l2.5 8v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Z" /><path d="M3 13h5l1.5 3h5l1.5-3h5" />',
        'info' => '<circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" />',
        'keyboard' => '<rect x="2" y="5" width="20" height="14" rx="2" /><path d="M6 9h.01M10 9h.01M14 9h.01M18 9h.01M8 12.5h.01M12 12.5h.01M16 12.5h.01M8 16h8" />',
        'languages' => '<path d="M3 5h9M7.5 3v2M5 5c.5 3.5 2.5 6.5 6 8M10 5c-.5 3.5-2.5 6.5-6 8" /><path d="m12 21 4.5-10 4.5 10M13.5 18h6" />',
        'link' => '<path d="M10 14a4.5 4.5 0 0 0 6.4 0l3.2-3.2a4.5 4.5 0 0 0-6.4-6.4L11.8 5.8" /><path d="M14 10a4.5 4.5 0 0 0-6.4 0l-3.2 3.2a4.5 4.5 0 0 0 6.4 6.4l1.4-1.4" />',
        'log-out' => '<path d="M10 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h4" /><path d="m15 8 4 4-4 4M19 12H9" />',
        'menu' => '<path d="M4 7h16M4 12h16M4 17h16" />',
        'minus' => '<path d="M5 12h14" />',
        'monitor' => '<rect x="3" y="4" width="18" height="12" rx="2" /><path d="M8 20h8M12 16v4" />',
        'moon' => '<path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z" />',
        'more-horizontal' => '<circle cx="5" cy="12" r="1" /><circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" />',
        'paperclip' => '<path d="M20 11.5l-8.2 8.2a5 5 0 0 1-7.1-7.1l8.5-8.5a3.3 3.3 0 0 1 4.7 4.7l-8.5 8.5a1.7 1.7 0 0 1-2.4-2.4L14.5 7" />',
        'pencil' => '<path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z" /><path d="m15 5 3 3" />',
        'play' => '<path d="M7 4.5v15l12.5-7.5Z" />',
        'plug' => '<path d="M9 3v5M15 3v5M12 17v4" /><path d="M6 8h12v3a6 6 0 0 1-12 0Z" />',
        'plus' => '<path d="M12 5v14M5 12h14" />',
        'receipt' => '<path d="M6 3h12v18l-3-2-3 2-3-2-3 2Z" /><path d="M9 8h6M9 12h6" />',
        'redo' => '<path d="M15 15l5-5-5-5" /><path d="M20 10H9.5a5.5 5.5 0 0 0 0 11H13" />',
        'search' => '<circle cx="11" cy="11" r="7" /><path d="m20 20-4-4" />',
        'settings' => '<path d="M10.2 5.2L10.7 2.6A9.5 9.5 0 0 1 13.3 2.6L13.8 5.2A7 7 0 0 1 15.5 5.9L17.7 4.4A9.5 9.5 0 0 1 19.6 6.3L18.1 8.5A7 7 0 0 1 18.8 10.2L21.4 10.7A9.5 9.5 0 0 1 21.4 13.3L18.8 13.8A7 7 0 0 1 18.1 15.5L19.6 17.7A9.5 9.5 0 0 1 17.7 19.6L15.5 18.1A7 7 0 0 1 13.8 18.8L13.3 21.4A9.5 9.5 0 0 1 10.7 21.4L10.2 18.8A7 7 0 0 1 8.5 18.1L6.3 19.6A9.5 9.5 0 0 1 4.4 17.7L5.9 15.5A7 7 0 0 1 5.2 13.8L2.6 13.3A9.5 9.5 0 0 1 2.6 10.7L5.2 10.2A7 7 0 0 1 5.9 8.5L4.4 6.3A9.5 9.5 0 0 1 6.3 4.4L8.5 5.9A7 7 0 0 1 10.2 5.2Z" /><circle cx="12" cy="12" r="3" />',
        'shield' => '<path d="M12 3 5 6v5c0 4.5 3 8.3 7 10 4-1.7 7-5.5 7-10V6Z" />',
        'sliders' => '<path d="M4 7h9M17 7h3M4 17h3M11 17h9" /><circle cx="15" cy="7" r="2" /><circle cx="9" cy="17" r="2" />',
        'star' => '<path d="M12 3.3l2.1 6.4h6.7l-5.4 4 2.1 6.4-5.5-4-5.5 4 2.1-6.4-5.4-4h6.7Z" />',
        'star-filled' => '<path d="M12 3.3l2.1 6.4h6.7l-5.4 4 2.1 6.4-5.5-4-5.5 4 2.1-6.4-5.4-4h6.7Z" fill="currentColor" />',
        'sun' => '<circle cx="12" cy="12" r="4" /><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" />',
        'tag' => '<path d="M3 5v6.2a2 2 0 0 0 .6 1.4l8.3 8.3a2 2 0 0 0 2.8 0l6.2-6.2a2 2 0 0 0 0-2.8L12.6 3.6A2 2 0 0 0 11.2 3H5a2 2 0 0 0-2 2Z" /><path d="M8 8h.01" />',
        'trash' => '<path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2" /><path d="m5 6 1 13a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-13" /><path d="M10 11v6M14 11v6" />',
        'undo' => '<path d="M9 15l-5-5 5-5" /><path d="M4 10h10.5a5.5 5.5 0 0 1 0 11H11" />',
        'user' => '<circle cx="12" cy="8" r="4" /><path d="M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1" />',
        'users' => '<circle cx="9" cy="8" r="3.5" /><path d="M3 20v-1a5 5 0 0 1 5-5h2a5 5 0 0 1 5 5v1M15.5 4.6a3.5 3.5 0 0 1 0 6.8M18 14.2a5 5 0 0 1 3 4.8v1" />',
        'video' => '<rect x="2" y="6" width="14" height="12" rx="2" /><path d="m16 10.5 6-3.5v10l-6-3.5" />',
        'wallet' => '<path d="M17 7V5a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h14a1 1 0 0 1 1 1v3M3 6v12a2 2 0 0 0 2 2h14a1 1 0 0 0 1-1v-3" /><path d="M21 12h-4a2 2 0 0 0 0 4h4Z" />',
        'warning' => '<path d="M10.3 4.2 2.8 17a2 2 0 0 0 1.7 3h15a2 2 0 0 0 1.7-3L13.7 4.2a2 2 0 0 0-3.4 0Z" /><path d="M12 9v4M12 17h.01" />',
        'zoom-in' => '<circle cx="11" cy="11" r="7" /><path d="m20 20-4-4M8 11h6M11 8v6" />',
        'zoom-out' => '<circle cx="11" cy="11" r="7" /><path d="m20 20-4-4M8 11h6" />',
    ];
    $body = $icons[(string) $name] ?? null;
    $mirrored = in_array((string) $name, ['chevron-end', 'chevron-start', 'external-link', 'log-out', 'redo', 'undo'], true);
    $width = in_array((float) $strokeWidth, [1.0, 1.5, 2.0, 2.5], true) ? (float) $strokeWidth : 2.0;

    if ($body === null) {
        throw new \InvalidArgumentException('Unknown icon ['.(string) $name.'].');
    }
@endphp

<svg
    {{ $attributes->class([$sizeClass, 'shrink-0', 'rtl:-scale-x-100' => $mirrored]) }}
    data-slot="icon"
    data-icon="{{ $name }}"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    stroke-width="{{ $width }}"
    stroke-linecap="round"
    stroke-linejoin="round"
    @if (filled($label)) role="img" aria-label="{{ $label }}" @else aria-hidden="true" @endif
>
    {!! $body !!}
</svg>
resources/views/components/ui/icon/tile.blade.php Blade
{{--
    Icon tile — the tinted square a feature card, contact row or integration
    chip leads with. Pass a named icon (`name`) or drop an inline <svg> in the
    slot; `tone` maps to the fill + glyph colour, `size` to the box and the
    glyph inside it. The tile is decorative by default; pass `label` for a
    tile that carries meaning on its own.
--}}
@props([
    'name' => null,
    'tone' => 'primary',
    'size' => 'md',
    'label' => null,
])

@php
    $styles = require base_path(config('ui.component_path', 'resources/views/components/ui').'/_styles.php');
    $recipe = $styles['icon-tile'] ?? [];

    $tone = array_key_exists($tone, $recipe['tones'] ?? []) ? $tone : 'primary';
    $size = array_key_exists($size, $recipe['sizes'] ?? []) ? $size : 'md';
    $classes = trim(($recipe['base'] ?? '').' '.($recipe['tones'][$tone] ?? '').' '.($recipe['sizes'][$size] ?? ''));
@endphp

<span
    data-slot="icon-tile"
    data-tone="{{ $tone }}"
    data-size="{{ $size }}"
    @if (filled($label)) role="img" aria-label="{{ $label }}" @else aria-hidden="true" @endif
    {{ $attributes->merge(['class' => $classes]) }}
>
    @if ($name !== null)
        <x-ui.icon :name="$name" />
    @else
        {{ $slot }}
    @endif
</span>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.11.0
Status
Stable
License
open
Accessibility reviewed
No review date recorded
Last breaking change
No date recorded
Deprecation
Not deprecated
Contract
v6
Foundation
≥ 1.0.0