---
title: Icons
description: The Lucide set ported into typed SVG constants, one cargo feature per Lucide category.
source: https://github.com/crabtalk/bezel/blob/main/crates/icons/src/lib.rs
---

> One page of the bezel documentation. The index is https://bezel.gallery/llms.txt

# Icons

```rust
use ui::icons::{self, Icon, glyph};
use ui::widgets::Icons;

theme.icon(glyph::Search)                        // the ladder's body step, in the text tone
theme.icon_at(TextStyle::Caption, glyph::Search) // another rung
icons::icon(glyph::Search).size(px(16.0)).text_color(theme.text_muted)
```

gpui resolves an svg's tone from that element's own style and never inherits one, so `icons::icon(..)` with no `text_color` anywhere paints **nothing** — no warning, no fallback. `theme.icon` is the same builder with the size and tone already in it.

## Sources

```rust
theme.row_icon(glyph::Monitor)                 // a glyph compiled in
theme.row_icon(Icon::asset("brand/mark.svg"))  // the app's own AssetSource
theme.row_icon(Icon::file(picked))             // a file on disk
```

Every component takes `impl Into<Icon>`, so a constant passes as itself and the component never learns which kind it got.

## Solid twins

```rust
theme.icon(Icon::glyph(glyph::Star).solid())
icons::solid(glyph::Star)                     // the same, for the common case
```

A property of the value rather than a second call, so a control can hold one `Icon` and flip the variant instead of branching between two functions.

## Features

```toml
bezel-icons = { version = "0.1", features = ["arrows", "navigation"] }
```

One per Lucide category, named as Lucide names them; `full` is all 42, and nothing is on by default. Cargo unions features across a graph, so `ui`'s own three — `arrows`, `notifications`, `text` — are the floor for anything depending on it.

## API

```rust
pub trait Icons: ThemeExt {
    /// Returns a gpui `Svg`, so a `Styled` call after it wins — the tone is a
    /// floor, not a decision.
    fn icon(&self, icon: impl Into<Icon>) -> Svg;

    /// Another rung of the ladder.
    fn icon_at(&self, role: TextStyle, icon: impl Into<Icon>) -> Svg;
}
```

```rust
// icons — an `Icon` carries no size and no colour: those belong to the
// component painting it.

impl Icon {
    pub const fn glyph(svg: &'static [u8]) -> Self;

    /// Resolved through the app's registered `AssetSource`.
    pub fn asset(key: impl Into<SharedString>) -> Self;

    /// Loaded off the paint thread and cached, so the first frame or two paint
    /// nothing.
    pub fn file(path: impl Into<SharedString>) -> Self;

    /// Fills the outline — filled *and* stroked, so the outer edge lands where
    /// the outline puts it and a control swapping between them does not jump.
    pub fn solid(self) -> Self;

    // ...
}

/// The bare builder: it carries no tone, so it needs one set on the glyph.
pub fn icon(icon: impl Into<Icon>) -> Svg;
pub fn solid(icon: impl Into<Icon>) -> Svg;

/// Every enabled category and its `(name, svg)` pairs, for an icon browser.
/// Naming it pins the whole enabled set.
pub const CATEGORIES: &[(&str, &[(&str, Icon)])];
```

An `Icon` carries no size and no colour: those belong to the component. Modules and constants are Lucide's own, generated by `crates/icons/build.rs` from a pinned release — bumping the version is the upgrade, and the diff says which glyphs upstream redrew. Lucide is ISC-licensed and asks for no attribution in a shipped binary.
