A lightweight, zero-dependency JavaScript icon picker designed for the Material Symbols variable font.
This picker provides access to over 2,000+ icons with full-text search, category filtering, and support for variable font axes (Fill, Weight, Grade, Optical Size).
- 📦 Zero Dependencies: Pure Vanilla JS. No jQuery, no extra bloat.
- 🎨 Variable Font Support: Toggle between Outlined, Rounded, and Sharp variants natively. Restrict to a subset with the
variantsoption — only the fonts you actually need are fetched. - 🙈 Broken Icon Filtering: Icons present in metadata but missing from the font file are automatically detected and hidden.
- 🌓 Smart Theming: Built-in Light and Dark modes, plus
automode (follows system settings). - ⚡ High Performance: Optimized rendering and virtual-style logic to handle the massive icon set smoothly.
- 🔍 Smart Search: Search by icon name or descriptive tags (e.g., searching "home" or "house").
The library automatically handles its own CSS injection and links the necessary Google Fonts.
<script src="material-symbols-picker.js"></script>You can also get it from jsdelivr:
<script src="https://cdn.jsdelivr.net/gh/Axsag/material-icons-picker@latest/material-symbols-picker.js"></script>The simplest way to start is by adding a data-icon-picker attribute to your input elements:
<input type="text" data-icon-picker value="face">
<script>
// Initializes all inputs with the data attribute
MaterialSymbolsPicker.init('[data-icon-picker]');
</script>If you need more control or want to react to changes:
const el = document.getElementById('my-input');
const picker = new MaterialSymbolsPicker(el, {
variant: 'rounded', // 'outlined' | 'rounded' | 'sharp'
variants: ['outlined', 'rounded'], // which variants to offer in the UI
theme: 'auto', // 'light' | 'dark' | 'auto'
fill: 0, // 0 or 1
onChange: (name) => {
console.log('Selected Icon:', name);
}
});| Option | Type | Default | Description |
|---|---|---|---|
variant |
string |
'outlined' |
The active Material Symbols style: 'outlined', 'rounded', or 'sharp'. |
variants |
string[] |
['outlined','rounded','sharp'] |
Which variants to offer in the picker UI. When only one is given the variant pills are hidden and only that font is fetched. |
fill |
number |
0 |
Fill axis (0 for stroke, 1 for solid). |
fills |
number[] |
[0,1] |
Which fills to offer in the picker UI. When only one is given the fill pills are hidden. |
weight |
number |
400 |
Font weight (100 through 700). |
grade |
number |
0 |
Weight fine-tuning (-25, 0, 200). |
size |
number |
24 |
Icon size in pixels for the trigger preview. |
theme |
string |
'auto' |
Color mode: 'light', 'dark', or 'auto'. |
fetchIcons |
boolean |
true |
Fetch the full metadata from Google (false uses a small fallback list). |
icons |
string[] |
null |
Provide a custom icon list directly, skipping the fetch entirely. |
onChange |
function |
null |
Callback function: (name) => { ... }. |
picker.getValue(): Returns the name of the currently selected icon.picker.setValue('icon_name'): Updates the selected icon programmatically.picker.setTheme('dark'): Switches the UI theme on the fly ('light','dark', or'auto').picker.destroy(): Cleans up the DOM and restores the original input element.
You can customize the UI labels by passing a strings object during initialization:
new MaterialSymbolsPicker(el, {
strings: {
placeholder: 'Select Icon...',
searchPlaceholder: 'Search...',
noResults: 'Nothing found',
allCategories: 'All Categories',
clear: 'Clear',
}
});Pass a categories map inside strings to override individual category labels. The key is the raw category value returned by the API; any category not listed falls back to its default English label.
new MaterialSymbolsPicker(el, {
strings: {
allCategories: 'Toutes les catégories',
categories: {
action: 'Action',
alert: 'Alerte',
av: 'Audio / Vidéo',
communication: 'Communication',
content: 'Contenu',
device: 'Appareil',
editor: 'Éditeur',
file: 'Fichier',
hardware: 'Matériel',
home: 'Maison',
image: 'Image',
maps: 'Cartes',
navigation: 'Navigation',
notification: 'Notification',
places: 'Lieux',
search: 'Recherche',
social: 'Social',
toggle: 'Bascule',
},
},
});The full list of known category keys: action, alert, av, communication, content, device, editor, file, hardware, home, image, maps, navigation, notification, places, search, social, toggle. Any category key not present in your map (or added by Google in a future update) is auto-formatted as a safe fallback (some_key → Some Key).
By default the picker offers all three variants via toggle pills. You can narrow this down:
// Lock to a single variant — pills disappear, only Rounded Fill is fetched
new MaterialSymbolsPicker(el, {
variant: 'rounded',
variants: ['rounded'],
fill: 1,
fills: [1]
});
// Offer two variants — only those two fonts are fetched
new MaterialSymbolsPicker(el, {
variants: ['outlined', 'sharp'],
});When variants contains only one entry the variant pill row is hidden entirely and only that font family is requested from Google Fonts, saving one unnecessary network request.