← Back to UI Components ← Back to Table of Contents

9.2 Bootstrap Icons

KMP templates primarily render Bootstrap Icons with bi CSS classes:

<i class="bi bi-calendar-event" aria-hidden="true"></i>

The authenticated application stylesheet, app/assets/css/app.css, currently imports Bootstrap Icons 1.11.3 from the versioned unpkg font stylesheet and then imports app/assets/css/bootstrap-icon-sizes.css. The public-event layout also loads that versioned stylesheet directly. The Vite build owns app.css; see Asset management.

KMP also bundles Font Awesome through @fortawesome/fontawesome-free. Do not mix bi-* and fa-* classes on one icon or assume that a name exists in both sets.

Template patterns

Use an icon plus visible text for actions whenever space permits:

<button type="button" class="btn btn-primary">
    <i class="bi bi-download me-2" aria-hidden="true"></i>
    <?= __('Export CSV') ?>
</button>

An icon-only control needs an accessible name and a useful visible tooltip only as a supplement:

<button
    type="button"
    class="btn btn-sm btn-outline-secondary"
    aria-label="<?= h(__('Edit member')) ?>"
    title="<?= h(__('Edit member')) ?>">
    <i class="bi bi-pencil" aria-hidden="true"></i>
</button>

Status must include text, not only color or an icon:

<span class="text-success">
    <i class="bi bi-check-circle-fill me-1" aria-hidden="true"></i>
    <?= __('Active') ?>
</span>

When an icon itself conveys an image or status without adjacent text, give its container an accessible name. Decorative icons must use aria-hidden="true".

Size and color

Icons inherit font-size and currentColor. Bootstrap utilities such as fs-4, text-success, and me-2 are usually sufficient. KMP’s additional size classes are defined in bootstrap-icon-sizes.css:

Prefer relative sizing that follows surrounding text. Large decorative icons must not displace labels, reduce touch targets, or obscure visible focus.

Dynamic icons

Treat an icon class derived from data as an allowlisted presentation value. Never concatenate untrusted input into a class or emit raw HTML.

<?php
$icons = [
    'active' => 'bi-check-circle-fill',
    'pending' => 'bi-clock',
    'inactive' => 'bi-x-circle',
];
$icon = $icons[$status] ?? 'bi-question-circle';
?>
<i class="bi <?= h($icon) ?>" aria-hidden="true"></i>
<span><?= h($statusLabel) ?></span>

Icon helpers

AppView conditionally loads Templating.Icon and Templating.IconSnippet when the optional templating classes are installed, and config/app.php declares a Bootstrap icon set. Existing Queue-plugin templates use this helper surface. The general KMP templates use bi class markup; follow the nearby template instead of converting styles opportunistically.

The helper’s configured metadata path and the CSS-font delivery path are separate concerns. A Vite build does not generate Bootstrap Icon metadata.

Finding an icon

Use the official Bootstrap Icons gallery and verify the selected icon exists in the pinned 1.11.3 set before committing it. Then search the codebase for an established KMP usage:

rg 'bi-calendar-event' app/templates app/plugins

Troubleshooting

If a bi icon does not display:

  1. Confirm the page loads app CSS or the public-event Bootstrap Icons stylesheet.
  2. Confirm the class includes both bi and the exact bi-{name}.
  3. Inspect the stylesheet request and font requests in the browser network panel.
  4. Run npm run dev from app/ after changing stylesheet imports.
  5. Check Content Security Policy and network availability when the remote font stylesheet is involved.

If a Font Awesome icon does not display, check its fa-* classes and the Vite-copied files under webroot/fonts; that is a different integration.