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 } from '@morphos/icons'
import { LucideSource } from '@morphos/icons/lucide'
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 (an optional peer dependency; install it only if you use this provider). It lives in its own entry, @morphos/icons/lucide, so apps that use only their own icon set never import lucide. 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

Once you import LucideSource from @morphos/icons/lucide, your editor autocompletes every lucide name on name — nothing else to set up. Any other string is still accepted, for names from your own providers.

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 | string—Icon 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 | CSSProperties—Inline style on the root <svg>.
classstring—CSS class on the root <svg>.
idstring—id on the root element.
aria-labelstring—Accessible 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