Icon
Renders an inline SVG icon from the icon set.
Installation
Included in poetry-ui — available as
poetry_icon
the moment you've installed Poetry,
with no per-component step. To own the source and edit it, copy it into your app:
bin/rails g poetry:add icon
Default
Open Default standalone
<div class="flex items-center gap-4">
<%= poetry_icon(name: :plus) %>
<%= poetry_icon(name: :"chevron-right") %>
<%= poetry_icon(name: :settings) %>
</div>
Animated
Open Animated standalone
<%# An icon is plain svg - Tailwind's animation utilities apply directly.
The spinning loader here is the raw ingredient only: for real loading
UI reach for poetry_spinner (it announces itself, role=status) or
Button's loading: swap. %>
<div class="flex flex-wrap items-center gap-6">
<%= poetry_icon(name: :"loader-circle", class: "animate-spin") %>
<%= poetry_icon(name: :"refresh-cw", class: "animate-spin") %>
<%= poetry_icon(name: :heart, class: "animate-pulse") %>
<%= poetry_icon(name: :bell, class: "animate-bounce") %>
</div>
Colors
Open Colors standalone
<%# Lucide draws with stroke="currentColor", so an icon inherits the text
color around it. Semantic text-* tokens keep the tint on-theme across
every style and color scheme with a single class. %>
<div class="flex flex-wrap items-center gap-4">
<%= poetry_icon(name: :"circle-check", class: "text-primary") %>
<%= poetry_icon(name: :info, class: "text-muted-foreground") %>
<%= poetry_icon(name: :"triangle-alert", class: "text-destructive") %>
</div>
Labeled
Open Labeled standalone
<%# A standalone icon carries meaning on its own: label: makes it role="img" with an aria-label. Without it, icons are decorative (aria-hidden). %>
<%= poetry_icon(name: :trash, label: "Delete") %>
Sizes
Open Sizes standalone
<%# Standalone icons render at Lucide's intrinsic 24px box (the svg
carries width/height="24"); a size-* utility beats the presentation
attributes. Inside poetry components the component's own svg sizing
wins regardless - this ladder is for icons standing alone. %>
<div class="flex flex-wrap items-end gap-4">
<%= poetry_icon(name: :feather, class: "size-3") %>
<%= poetry_icon(name: :feather, class: "size-4") %>
<%= poetry_icon(name: :feather, class: "size-5") %>
<%= poetry_icon(name: :feather) %>
<%= poetry_icon(name: :feather, class: "size-8") %>
<%= poetry_icon(name: :feather, class: "size-10") %>
</div>
Stroke width
Open Stroke width standalone
<%# Lucide glyphs are drawn at stroke-width="2"; a stroke-* utility beats
the presentation attribute and re-weights the line. The weight holds
its ratio at any size (the viewBox scales stroke with the glyph). %>
<div class="flex flex-wrap items-center gap-4">
<%= poetry_icon(name: :feather, class: "size-8 stroke-1") %>
<%= poetry_icon(name: :feather, class: "size-8 stroke-[1.5px]") %>
<%= poetry_icon(name: :feather, class: "size-8 stroke-2") %>
<%= poetry_icon(name: :feather, class: "size-8 stroke-3") %>
</div>
With tooltip
Open With tooltip standalone
Notifications
Archive
Move to trash
<%# The icon-button pattern: Button's label: carries the accessible name
(required on size: :icon), the tooltip mirrors it for sighted hover
(aria-describedby lands on open). The icon itself stays decorative. %>
<div class="flex flex-wrap items-center gap-1">
<%= poetry_tooltip do |tooltip| %>
<% tooltip.with_trigger(variant: :ghost, size: :icon, label: "Notifications") do %>
<%= poetry_icon(name: :bell) %>
<% end %>
Notifications
<% end %>
<%= poetry_tooltip do |tooltip| %>
<% tooltip.with_trigger(variant: :ghost, size: :icon, label: "Archive") do %>
<%= poetry_icon(name: :archive) %>
<% end %>
Archive
<% end %>
<%= poetry_tooltip do |tooltip| %>
<% tooltip.with_trigger(variant: :ghost, size: :icon, label: "Move to trash") do %>
<%= poetry_icon(name: :trash) %>
<% end %>
Move to trash
<% end %>
</div>
API
Poetry::Ui::Icon::Component — options are
constructor keywords (the poetry_* helper forwards them);
slots are composed inside the block. Generated from the gem's source documentation.
| Option | Type | Details | Description |
|---|---|---|---|
| label: | String | The accessible name - given, the icon is standalone (role=img); absent, it is decorative (aria-hidden). | |
| library: | Symbol | Per-render icon set override (defaults to config.icon_library). | |
| name: | Symbol | required; format: :"icon-name" |
The icon's name in the active set. format: :\"icon-name\" is the machine-readable value contract: the registry carries it, and literal names are validated against the icon set statically - a misspelled name is caught before it can crash a render. |
Styling
Every part carries a stable data-slot attribute — target
[data-slot=…] from your own CSS to restyle it. State rides
data attributes on the parts below. This contract is verified against rendered DOM in CI.
| Part | Description |
|---|---|
| [data-slot=icon] | The <svg> root itself - the vendored icon markup renders inside; ARIA (label: vs decorative) rides here |