Morphos
Icons

Icon

Renders an SVG icon by name, resolved against the provider configured with IconProvider.

Interactive example

Open in Storybook

Installation

npm install @morphos/icons
pnpm add @morphos/icons
yarn add @morphos/icons
bun add @morphos/icons

Import

import { Icon } from '@morphos/icons'

Usage

Icon resolves name against whichever provider is currently configured. That provider is set with IconProvider, which is mandatory — every app applies it once, at the root, before any Icon renders:

import { Icon, IconProvider, LucideSource } from '@morphos/icons'
import { Component } from '@praxisjs/decorators'
import { StatefulComponent } from '@praxisjs/core'

@IconProvider(LucideSource)
@Component()
class App extends StatefulComponent {
  render() {
    return <Icon name="Plus" aria-label="Add item" />
  }
}

LucideSource is the built-in provider — a pre-configured wrapper around lucide (a real peer dependency; its icon data is read live, import { icons } from "lucide" under the hood). It still has to be applied through IconProvider explicitly, like any other provider — there is no default.

npm install lucide
pnpm add lucide
yarn add lucide
bun add lucide

name is typed against LucideSource's icon names, so your editor autocompletes every valid lucide export — plain strings are still accepted, for provider names the package can't know about ahead of time.

Overriding the provider per instance

Once IconProvider has configured an app-wide provider, every Icon without a provider prop resolves against it. Pass provider to resolve a single icon against a different, already-registered provider instead:

<Icon name="logo" provider="brand" />

See IconProvider for registering a custom provider like "brand".

Props

PropTypeDefaultDescription
nameLucideIconName | stringIcon name, resolved against the configured provider. Required.
provider"lucide" | stringconfigured providerOverrides the configured provider for this instance only.
sizenumber | string24Applied to both width and height.
colorstring"currentColor"Icon color — stroke for a structured (nodes) provider like lucide, or whatever the source markup itself declares for an { svg } provider.
strokeWidthnumber | string2Structured (nodes) providers only.
absoluteStrokeWidthbooleanfalseStructured (nodes) providers only — scales strokeWidth so the visual stroke thickness stays constant across sizes.
stylestring | CSSPropertiesInline style on the root <svg>.
classstringCSS class on the root <svg>.
idstringid on the root element.
aria-labelstringAccessible name. When set, the icon gets role="img"; otherwise it's aria-hidden.

Accessibility

Icons are decorative by default: aria-hidden="true" and no role. Pass aria-label when the icon conveys meaning on its own — an icon-only button with no visible text, for example — and Icon switches to role="img" with that label instead of hiding itself.

Bundle size

Resolving by name means lucide's icon data ships as one object, not per-icon imports — there's no tree-shaking per icon. It's small in absolute terms (path data only, not rendered markup), but if that's ever a concern, a custom provider backed by RegisterIconProvider and a glob path only includes the icons you actually reference.

Icon never throws. It logs a console warning and renders nothing both when no provider is configured at all (IconProvider was never applied) and when name doesn't exist for the resolved provider — a typo reaching you through untyped/dynamic code, for example.

On this page