dioxus_icon_component/lib.rs
1// Copyright (c) 2026 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
2// Use of this source is governed by Apache-2.0 License
3// that can be found in the LICENSE file.
4
5use dioxus::prelude::*;
6
7/// This trait is used to override `IconProps`.
8///
9/// Implements this trait when adding a new real icon.
10pub trait IconShape: Clone + PartialEq + 'static {
11 /// Returns the SVG child elements (paths, circles, etc.) that define the icon shape.
12 ///
13 /// # Errors
14 ///
15 /// Returns `Err` if rendering the child elements fails.
16 fn child_elements(&self) -> Element;
17
18 /// Default title text for the SVG element.
19 const TITLE: Option<&'static str> = None;
20
21 /// Default width of the SVG element in pixels.
22 const WIDTH: Option<&'static str> = None;
23
24 /// Default height of the SVG element in pixels.
25 const HEIGHT: Option<&'static str> = None;
26
27 /// Default fill color of the SVG element.
28 const FILL: Option<&'static str> = Some("currentColor");
29
30 /// Default stroke color of the SVG element.
31 const STROKE: Option<&'static str> = None;
32
33 /// Default stroke width of the SVG element (e.g., "2").
34 const STROKE_WIDTH: Option<&'static str> = None;
35
36 /// Default stroke line cap style (e.g., "round", "butt", "square").
37 const STROKE_LINE_CAP: Option<&'static str> = None;
38
39 /// Default stroke line join style (e.g., "round", "miter", "bevel").
40 const STROKE_LINE_JOIN: Option<&'static str> = None;
41
42 /// Default view box string (e.g., "0 0 24 24").
43 const VIEW_BOX: Option<&'static str> = None;
44
45 /// Default XML namespace for the SVG element.
46 /// Falls back to `"http://www.w3.org/2000/svg"` if not set.
47 const XMLNS: Option<&'static str> = Some("http://www.w3.org/2000/svg");
48}
49
50/// Props for the `Icon` component.
51///
52/// All fields are optional except `icon`. When a field is not provided,
53/// the default value from the associated `IconShape` implementation is used.
54#[derive(Clone, PartialEq, Props)]
55pub struct IconProps<T: IconShape> {
56 /// The icon shape implementation that provides SVG child elements.
57 pub icon: T,
58
59 /// Optional title text rendered as a `<title>` element inside the SVG for accessibility.
60 #[props(default = None)]
61 pub title: Option<&'static str>,
62
63 /// Additional HTML/SVG global attributes to spread onto the `<svg>` element.
64 /// Allows passing standard attributes like `id`, `aria-*`, event handlers, etc.
65 #[props(extends = GlobalAttributes)]
66 pub attributes: Vec<Attribute>,
67}
68
69/// # Errors
70///
71/// Returns `Err` if rendering the icon fails.
72#[allow(non_snake_case)]
73pub fn Icon<T: IconShape>(props: IconProps<T>) -> Element {
74 rsx! {
75 svg {
76 width: T::WIDTH,
77 height: T::HEIGHT,
78 fill: T::FILL,
79 stroke: T::STROKE,
80 stroke_width: T::STROKE_WIDTH,
81 stroke_linecap: T::STROKE_LINE_CAP,
82 stroke_linejoin: T::STROKE_LINE_JOIN,
83 view_box: T::VIEW_BOX,
84 xmlns: T::XMLNS,
85
86 ..props.attributes,
87
88 if let Some(title_text) = props.title {
89 title {{ title_text }}
90 } else if let Some(title_text) = T::TITLE {
91 title {{ title_text }}
92 }
93
94 {props.icon.child_elements()}
95 }
96 }
97}