Skip to main content

CnIconBrowser

A searchable, visual icon picker. The library imports no icon package — the consuming app owns that choice and injects a normalized catalogue via the icons prop. The default Icons tab browses that catalogue through a search box and a capped grid; the optional Custom tab offers curated image-URL icons (urlIcons) and — when an uploadFn is supplied — an upload control.

Vue 2 v-model: value in, input out — a single string. What it holds is the catalogue's choice (see the adapters): an SVG path for @mdi/js, a component name for vue-material-design-icons, or a URL for a custom/uploaded image.

The search box is fuzzy and separator-insensitive: it matches on each entry's label and key as an order-preserving subsequence, ignoring spaces/dashes/case. So CalendarRange, calendar range, calendarrange and cal rng all find Calendar Range; results are ranked best-match first.

Supplying a catalogue

Two adapters turn a popular icon source into the icons shape:

<!-- @mdi/js (path strings, self-contained values) -->
<script>
import * as mdi from '@mdi/js'
import { mdiCatalogue } from '@conduction/nextcloud-vue'
export default { computed: { icons() { return mdiCatalogue(mdi) } } }
</script>
<template><CnIconBrowser v-model="icon" :icons="icons" /></template>
// vue-material-design-icons (Vue components — the Nextcloud-native set).
// Use a LAZY require-context so only the visible icons load.
import { vmdiCatalogue } from '@conduction/nextcloud-vue'
const ctx = require.context('vue-material-design-icons', false, /\.vue$/, 'lazy')
const icons = vmdiCatalogue(ctx) // each entry emits the component name, e.g. 'CalendarRange'

A catalogue entry is { key, label, value, search?, path?, component? }; the browser renders path inline as <svg> or component via <component :is>, and emits the entry's value. You can also build catalogues by hand.

Note: @mdi/js and vue-material-design-icons are generated from the same Material Design Icons master — identical icons. Pick by what your app already depends on and how you want to render the stored value (a path renders anywhere; a component name needs the package present).

By default the picker is a trigger button that opens the panel in a popover — tidy for forms and dense rows. Pass inline to render the panel always-open (good inside a roomy settings panel):

<CnIconBrowser v-model="icon" :icons="icons" inline />

See mdiCatalogue and vmdiCatalogue.

Props

NameTypeDefaultDescription
valueStringnullCurrent selection (v-model) — the catalogue's emitted value (path / name / …), a URL, or null.
modelValueStringundefinedThe same value under Vue 3's v-model name. v-model binds THIS, not value — both are accepted.
iconsArray[]The catalogue to browse: [{ key, label, value, search?, path?, component? }]. Build with mdiCatalogue / vmdiCatalogue.
urlIconsArray[]Curated image-URL icons for the Custom tab: [{ label, url }]. Each emits its url when picked.
urlIconGroupsArray[]Curated image-URL icons split into named groups, rendered on the Custom tab as one sub-tab per group with its own search: [{ key, label, icons: [{ id?, label, url }] }]. Use instead of the flat urlIcons for large packs such as the bundled NL Design catalogues (NL_DESIGN_ICON_GROUPS).
uploadFnFunctionnullInjected upload transport async (dataUrl) => ({ url }). When null, the upload control is hidden.
maxResultsNumber150Maximum icon cells rendered in the grid; a hint shows when matches exceed the cap.
defaultIconsArray[]Catalogue keys shown when the search box is empty. Falls back to the first maxResults in catalogue order.
inlineBooleanfalseRender the panel always-open inline. Off (default) renders a trigger button that opens the panel in a popover.
showLabelsBooleanfalseShow the human label under each icon cell.
allowUrlBooleanfalseAdd a free-text image-URL input to the Custom tab, so the picker can also hold an arbitrary URL (the icon-or-URL fields).
labelString''Optional field label rendered above the control (convenience for form fields).
clearableBooleanfalseOffer a control to unset the icon (emits null). Use for optional icon fields, where a picked icon would otherwise be impossible to remove.
sourcesArray[]Ordered catalogue source keys, one tab each (e.g. ['mdi', 'fontawesome', 'opengemeenten']). Empty renders a single "Icons" tab over the resolved icons.
allowCustomSvgBooleanfalseOffer a tab for authoring a raw <svg> icon by hand.

Why two props. Vue 3 compiles v-model="x" to :modelValue + @update:modelValue. A component declaring only value/input never receives the prop and its emit is never heard — silently. value is kept as the public name for existing consumers; modelValue is what a plain v-model binds, and both emit on every change.

Catalogue injection

When no icons prop is passed, CnIconBrowser uses an app-provided catalogue from Vue provide('cnIconCatalogue', catalogue) — handy for deeply-nested forms that can't easily thread a prop. If neither is present, it falls back to a small curated set (built from the library's bundled vue-material-design-icons) so the picker still works. Pair with CnWidgetIcon / CnDashboardIcon, which render whatever value the catalogue emits (path / registry name / URL).

Events

NameDescription
inputEmitted with the new icon value — an SVG path string, a URL, or null.

Slots

NameDescription
triggerPopup-mode trigger (default). Scoped: { open, toggle, value, label }.
emptyShown when no icons match the search query.

See also CnDashboardIcon for rendering (it understands path strings, URLs, and registry keys) and CnIconPicker for the simpler curated-registry picker.