BEEQ ships an <bq-icon> web component that loads SVG files on demand. By default, icons are sourced from Phosphor Icons, but you can point the component at any CDN or local folder containing SVG files.
How the icon system works
The bq-icon component:
- Reads the
name prop and appends .svg to construct a filename (e.g. bell-ringing.svg).
- Resolves the full URL by prepending the base path set via
setBasePath.
- Fetches the SVG over HTTP and inlines it into the component’s Shadow DOM.
Because icons are fetched at runtime, the SVG assets must be accessible from the browser — either hosted on a CDN or copied into your project’s output directory.
Setting the base path
Call setBasePath once at application startup, before any bq-icon components render:
import { setBasePath } from '@beeq/core';
// Local icons copied to your output directory
setBasePath('/assets/svg/');
Copying icons from node_modules
The SVG assets live in node_modules/@beeq/core/dist/beeq/svg. Copy them to your output directory using your bundler:
import { defineConfig } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';
export default defineConfig({
plugins: [
viteStaticCopy({
targets: [
{
src: './node_modules/@beeq/core/dist/beeq/svg/*',
dest: 'assets/svg',
},
],
}),
],
});
Then set the path:import { setBasePath } from '@beeq/core';
setBasePath('assets/svg');
{
"assets": [
{
"glob": "**/*",
"input": "node_modules/@beeq/core/dist/beeq/svg",
"output": "assets/svg/"
}
]
}
import { setBasePath } from '@beeq/core';
setBasePath('/assets/svg/');
Using bq-icon
Once the base path is set, use <bq-icon> anywhere in your templates:
<!-- Basic usage -->
<bq-icon name="bell-ringing"></bq-icon>
<!-- Custom size (in pixels) -->
<bq-icon name="bell-ringing" size="32"></bq-icon>
<!-- Custom color using a palette token -->
<bq-icon name="bell-ringing" color="text--brand" size="24"></bq-icon>
<!-- Accessible label -->
<bq-icon name="warning" label="Warning" size="24"></bq-icon>
<!-- Custom source (bypasses name + base path) -->
<bq-icon src="/my-icons/custom-icon.svg" size="24"></bq-icon>
Props reference
| Prop | Type | Default | Description |
|---|
name | string | — | Icon filename (without .svg) to load from the base path |
size | string | number | 24 | Width and height of the SVG in pixels |
color | string | — | Stroke color; accepts palette token values (e.g. text--brand) |
label | string | "{name} icon" | Accessible label for screen readers |
src | string | — | Direct URL to an SVG file; overrides name |
CSS custom properties
| Property | Default | Description |
|---|
--bq-icon--color | currentColor | SVG stroke color |
--bq-icon--size | 24px | SVG width and height |
Using external icon libraries
You can use any SVG icon library by pointing setBasePath at its CDN endpoint. The name prop must match the filenames provided by that library.
Heroicons example
import { setBasePath } from '@beeq/core';
// Heroicons 2.x — 24px outline style
setBasePath('https://cdn.jsdelivr.net/npm/[email protected]/24/outline');
<!-- Loads https://cdn.jsdelivr.net/npm/[email protected]/24/outline/bell.svg -->
<bq-icon name="bell" size="24"></bq-icon>
<!-- Loads https://cdn.jsdelivr.net/npm/[email protected]/24/outline/academic-cap.svg -->
<bq-icon name="academic-cap" size="24"></bq-icon>
When using an external library, icon names must exactly match the SVG filenames provided by that library. Phosphor Icons names (the BEEQ default) will not work with Heroicons, and vice versa.
RTL support
The icon component respects the --bq-icon--direction CSS custom property, which is automatically flipped when dir="rtl" is set on a parent element:
/* Set automatically by BEEQ's global styles */
:root { --bq-icon--direction: 1; } /* LTR */
[dir='rtl'] { --bq-icon--direction: -1; } /* RTL — icons are mirrored */
Events
The bq-icon component emits a single event:
| Event | Description |
|---|
svgLoaded | Emitted after the SVG content has been successfully fetched and rendered |
const icon = document.querySelector('bq-icon');
icon.addEventListener('svgLoaded', (event) => {
console.log('SVG content loaded:', event.detail);
});