Back to flin
flin

Integración de biblioteca de íconos

Cómo FlinUI integra más de 1,000 íconos Lucide como componentes integrados -- disponibles sin importaciones, renderizados como SVG en línea, personalizables en tamaño y color.

Thales & Claude | March 30, 2026 9 min flin
EN/ FR/ ES
flinrust

Icons are the vocabulary of user interfaces. A trash can means delete. A pencil means edit. A magnifying glass means search. Without icons, every action needs a text label. With icons, the interface communicates instantly, crossing language barriers -- particularly important for a language built in Abidjan for developers across Africa.

Sessions 049 and 209 integrated a complete icon library into FlinUI. Over 1,000 icons from the Lucide icon set, rendered as inline SVG, available with the same zero-import philosophy as every other FlinUI component. No font files to load. No icon sprite sheets to configure. Just <Icon name="home" /> and the icon appears.

El componente Icon

flin<Icon name="home" />
<Icon name="user" size={24} />
<Icon name="check" color="green" />
<Icon name="alert-triangle" size={20} color="warning" />
<Icon name="settings" size={32} stroke_width={1.5} />

The Icon component accepts four props:

PropTypeDefaultDescription
nametextrequiredIcon name from the Lucide set
sizeint24Width and height in pixels
colortext"currentColor"Fill/stroke color
stroke_widthfloat2SVG stroke width

Using "currentColor" as the default color means icons inherit their color from the surrounding text. An icon inside a <Text color="primary"> element will be the primary color. An icon inside a <Button variant="danger"> will be the danger color. This default eliminates the most common icon styling need without any explicit configuration.

Por qué Lucide

We evaluated four icon libraries:

LibraryIconsSizeLicenseStyle
Feather28724KBMITMinimal stroke
Heroicons29235KBMITSolid and outline
Font Awesome7,800+400KB+Mixed (free/pro)Varied
Lucide1,000+150KBISCClean stroke

Lucide won on three criteria:

Coverage. 1,000+ icons cover every common UI need. Feather and Heroicons, while beautifully designed, are missing icons for many domains (finance, medical, education, e-commerce).

License. Lucide uses the ISC license -- permissive, simple, and compatible with any use. Font Awesome's dual-license model (free tier plus paid pro tier) would create confusion for FLIN developers.

Design consistency. Every Lucide icon uses the same 24x24 grid, 2px stroke width, and rounded line caps. They look uniform when mixed, which is essential for a component library where icons appear in buttons, navigation items, form labels, and status indicators.

Lineage. Lucide is a fork of Feather Icons with active community development. It inherits Feather's exceptional design quality while adding the breadth that Feather lacks.

Arquitectura de integración

Icons are stored as SVG path data in a registry file. When <Icon name="home" /> renders, the component looks up the path data by name and constructs an inline SVG:

flin// Icon.flin (simplified)
name = props.name
size = props.size || 24
color = props.color || "currentColor"
stroke = props.stroke_width || 2

// Look up the SVG path data
path_data = icon_registry[name]

{if path_data != none}
    <svg
        width={size}
        height={size}
        viewBox="0 0 24 24"
        fill="none"
        stroke={color}
        stroke-width={stroke}
        stroke-linecap="round"
        stroke-linejoin="round"
    >
        <raw>{path_data}</raw>
    </svg>
{else}
    <span title="Icon not found: {name}">?</span>
{/if}

The icon_registry is a map from icon names to SVG path strings. For the "home" icon:

flinicon_registry["home"] = '<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>'

The <raw> tag (covered in article 094) injects the SVG path data as raw HTML, bypassing FLIN's HTML escaping. This is safe because the path data comes from the icon registry (a compile-time constant), not from user input.

SVG en línea vs. fuentes de íconos

FlinUI renders icons as inline SVG rather than using icon fonts (like Font Awesome's webfont approach). The reasons:

Scalability. Inline SVG scales perfectly at any size. Icon fonts can produce blurry edges at non-standard sizes because the browser's text rendering engine is optimized for text, not icons.

Color control. Inline SVG supports stroke and fill independently. Icon fonts render as text glyphs and can only be colored with color -- you cannot have a two-tone icon with a font.

No flash of invisible text. Icon fonts require a font file download. Until the font loads, icons are invisible (FOIT -- Flash of Invisible Text) or display as unicode squares. Inline SVG renders immediately because the path data is embedded in the HTML.

Tree shaking. When using inline SVG, only the icons actually used in the application are included. With an icon font, the entire font file (containing all icons) must be downloaded even if the application uses only five icons.

Accessibility. Inline SVG can include <title> and aria-label attributes for screen readers. Icon fonts are invisible to assistive technology unless wrapped in additional ARIA markup.

Categorías de íconos

The 1,000+ Lucide icons are organized by domain:

Navigation:    home, menu, arrow-left, arrow-right, chevron-down, external-link
Actions:       plus, minus, x, check, edit, trash, copy, save, download, upload
Communication: mail, phone, message-circle, send, bell, at-sign
Media:         play, pause, volume, camera, image, film, music
Files:         file, folder, archive, clipboard, paperclip
Users:         user, users, user-plus, user-minus, user-check
Data:          bar-chart, pie-chart, trending-up, activity, database
Development:   code, terminal, git-branch, bug, cpu, server
Commerce:      shopping-cart, credit-card, dollar-sign, package, truck
Social:        github, twitter, facebook, instagram, linkedin
Misc:          settings, search, filter, globe, map, clock, calendar, star

Uso de íconos en componentes

Icons integrate naturally with other FlinUI components:

flin// Button with icon
<Button variant="primary">
    <Icon name="save" size={16} /> Save
</Button>

// Navigation with icons
<Sidebar>
    <SidebarItem icon="home" href="/">Dashboard</SidebarItem>
    <SidebarItem icon="users" href="/users">Users</SidebarItem>
    <SidebarItem icon="shopping-cart" href="/orders">Orders</SidebarItem>
    <SidebarItem icon="settings" href="/settings">Settings</SidebarItem>
</Sidebar>

// Alert with icon
<Alert variant="warning">
    <Icon name="alert-triangle" /> This action cannot be undone.
</Alert>

// Empty state with large icon
<Center>
    <Stack align="center" gap={4}>
        <Icon name="inbox" size={48} color="muted" />
        <Text size="lg" color="muted">No messages</Text>
    </Stack>
</Center>

Many FlinUI components accept an icon prop directly, handling the <Icon> rendering internally:

flin// The icon prop is a shorthand
<SidebarItem icon="home">Dashboard</SidebarItem>

// Equivalent to
<SidebarItem>
    <Icon name="home" size={20} /> Dashboard
</SidebarItem>

Integración con métodos de cadena

Session 050's string methods play a role in icon handling. The starts_with and remove_prefix methods enable icon namespace detection:

flin// Some components need to detect icon prefixes
fn resolve_icon(icon_name: text) {
    {if icon_name.starts_with("lucide-")}
        return icon_name.remove_prefix("lucide-")
    {else if icon_name.starts_with("custom-")}
        return lookup_custom_icon(icon_name.remove_prefix("custom-"))
    {else}
        return icon_name
    {/if}
}

This pattern enables extensibility -- developers can add custom icon sets with a namespace prefix, and the icon system resolves them alongside the built-in Lucide icons.

Rendimiento: tamaño del registro de íconos

The complete Lucide icon registry (1,000+ icons as SVG path strings) is approximately 150KB of FLIN source. Compiled into bytecode, it is approximately 80KB. This is loaded once when the application starts and shared across all icon references.

For comparison: - Lucide as a JavaScript library: ~290KB (all icons) - Lucide as a web font: ~180KB - Font Awesome Free font: ~400KB - FlinUI icon registry: ~80KB (compiled)

The registry is smaller than the alternatives because it stores only the SVG path data -- no JavaScript module wrappers, no font metadata, no glyph tables. Just the raw coordinates that define each icon's shape.

Íconos personalizados

Developers can add custom icons to the registry:

flin// Register a custom icon
register_icon("my-logo", '<circle cx="12" cy="12" r="10"/><path d="M12 6v12M6 12h12"/>')

// Use it like any other icon
<Icon name="my-logo" size={32} color="primary" />

register_icon adds an entry to the icon registry. The custom icon is then available everywhere in the application, with the same props (size, color, stroke_width) as built-in icons.

For complete icon sets, a .flin file can register all icons at once:

flin// custom-icons.flin
register_icon("brand-logo", '<path d="..."/>')
register_icon("brand-icon-1", '<path d="..."/>')
register_icon("brand-icon-2", '<path d="..."/>')

This file is automatically discovered by the component system (if placed in a search path) and executed on startup. No import needed -- just drop the file in the project.

Mil íconos, cero configuración

Accesibilidad: íconos que hablan

Icons need to be accessible. A sighted user sees a trash can and understands "delete." A screen reader user hears nothing unless the icon has an accessible label.

FlinUI's Icon component handles this automatically:

flin// Decorative icon (next to text, no label needed)
<Button><Icon name="save" size={16} /> Save</Button>
// The button text "Save" provides the accessible name

// Standalone icon (no text, needs label)
<button click={delete_item} aria-label="Delete item">
    <Icon name="trash" size={20} />
</button>

// Icon with explicit title
<Icon name="info" size={16} title="More information" />
// Adds <title> element inside SVG for screen readers

When the title prop is provided, the Icon component adds a <title> element inside the SVG and an aria-labelledby attribute referencing it. Screen readers announce the title text when the icon receives focus.

For decorative icons (icons that appear next to text and do not carry independent meaning), the SVG includes aria-hidden="true" to prevent screen readers from announcing the SVG structure. This is set automatically when no title prop is provided.

El problema de búsqueda de íconos

With 1,000+ icons, finding the right one is a challenge. What is the icon for "calendar"? Is it calendar, calendar-days, calendar-check, or calendar-range? For the FlinUI documentation site, we built an interactive icon browser:

flinsearch = ""
filtered = icon_names.where(name => name.contains(search.lower))

<Input value={search} placeholder="Search icons..." />
<Grid cols={6} cols_md={8} cols_lg={10} gap={2}>
    {for name in filtered.take(100)}
        <Stack align="center" gap={1}>
            <Icon name={name} size={24} />
            <Text size="xs" color="muted">{name}</Text>
        </Stack>
    {/for}
</Grid>

This component searches across all icon names in real-time. Type "arrow" and you see all 20+ arrow variants. Type "chart" and you see all chart-related icons. The filter uses FLIN's built-in where and contains methods -- no search library needed.

Over 1,000 icons. Inline SVG rendering. Scalable to any size. Colorable with any token. Accessible with aria labels. Tree-shaken to include only used icons. Available with <Icon name="..." /> and nothing else.

Icons are the most frequently used visual element in web applications after text. Making them available without configuration, without downloads, without build steps is one of the decisions that makes FlinUI feel like it was designed for building real applications, not demos.


Esta es la Parte 87 de la serie "Cómo construimos FLIN", que documenta cómo un CEO en Abiyán y un CTO de IA integraron más de 1,000 íconos en una biblioteca de componentes UI.

Navegación de la serie: - [86] El sistema de diseño de página - [87] Integración de biblioteca de íconos (estás aquí) - [88] Componentes empresariales de FlinUI - [89] CSS con alcance y estilos computados

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles