dioxus_document/elements/
link.rs

1use super::*;
2use crate::document;
3use dioxus_html as dioxus_elements;
4
5#[non_exhaustive]
6#[derive(Clone, Props, PartialEq)]
7pub struct OtherLinkProps {
8    pub rel: String,
9    #[props(extends = link, extends = GlobalAttributes)]
10    pub additional_attributes: Vec<Attribute>,
11}
12
13#[non_exhaustive]
14#[derive(Clone, Props, PartialEq)]
15pub struct LinkProps {
16    pub rel: Option<String>,
17    pub media: Option<String>,
18    pub title: Option<String>,
19    pub disabled: Option<bool>,
20    pub r#as: Option<String>,
21    pub sizes: Option<String>,
22    /// Links are deduplicated by their href attribute
23    pub href: Option<String>,
24    pub crossorigin: Option<String>,
25    pub referrerpolicy: Option<String>,
26    pub fetchpriority: Option<String>,
27    pub hreflang: Option<String>,
28    pub integrity: Option<String>,
29    pub r#type: Option<String>,
30    pub blocking: Option<String>,
31    #[props(extends = link, extends = GlobalAttributes)]
32    pub additional_attributes: Vec<Attribute>,
33}
34
35impl LinkProps {
36    /// Get all the attributes for the link tag
37    pub fn attributes(&self) -> Vec<(&'static str, String)> {
38        let mut attributes = Vec::new();
39        extend_attributes(&mut attributes, &self.additional_attributes);
40        if let Some(rel) = &self.rel {
41            attributes.push(("rel", rel.clone()));
42        }
43        if let Some(media) = &self.media {
44            attributes.push(("media", media.clone()));
45        }
46        if let Some(title) = &self.title {
47            attributes.push(("title", title.clone()));
48        }
49        if let Some(disabled) = &self.disabled {
50            attributes.push(("disabled", disabled.to_string()));
51        }
52        if let Some(r#as) = &self.r#as {
53            attributes.push(("as", r#as.clone()));
54        }
55        if let Some(sizes) = &self.sizes {
56            attributes.push(("sizes", sizes.clone()));
57        }
58        if let Some(href) = &self.href {
59            attributes.push(("href", href.clone()));
60        }
61        if let Some(crossorigin) = &self.crossorigin {
62            attributes.push(("crossOrigin", crossorigin.clone()));
63        }
64        if let Some(referrerpolicy) = &self.referrerpolicy {
65            attributes.push(("referrerPolicy", referrerpolicy.clone()));
66        }
67        if let Some(fetchpriority) = &self.fetchpriority {
68            attributes.push(("fetchPriority", fetchpriority.clone()));
69        }
70        if let Some(hreflang) = &self.hreflang {
71            attributes.push(("hrefLang", hreflang.clone()));
72        }
73        if let Some(integrity) = &self.integrity {
74            attributes.push(("integrity", integrity.clone()));
75        }
76        if let Some(r#type) = &self.r#type {
77            attributes.push(("type", r#type.clone()));
78        }
79        if let Some(blocking) = &self.blocking {
80            attributes.push(("blocking", blocking.clone()));
81        }
82        attributes
83    }
84}
85
86/// Render a [`link`](crate::elements::link) tag into the head of the page.
87///
88/// > The [Link](https://docs.rs/dioxus-router/latest/dioxus_router/components/fn.Link.html) component in dioxus router and this component are completely different.
89/// > This component links resources in the head of the page, while the router component creates clickable links in the body of the page.
90///
91/// # Example
92/// ```rust, no_run
93/// # use dioxus::prelude::*;
94/// fn RedBackground() -> Element {
95///     rsx! {
96///         // You can use the meta component to render a meta tag into the head of the page
97///         // This meta tag will redirect the user to the dioxuslabs homepage in 10 seconds
98///         document::Link {
99///             href: asset!("/assets/style.css"),
100///             rel: "stylesheet",
101///         }
102///     }
103/// }
104/// ```
105///
106/// <div class="warning">
107///
108/// Any updates to the props after the first render will not be reflected in the head.
109///
110/// </div>
111#[doc(alias = "<link>")]
112#[component]
113pub fn Link(props: LinkProps) -> Element {
114    use_update_warning(&props, "Link {}");
115
116    use_hook(|| {
117        let document = document();
118        let mut insert_link = document.create_head_component();
119        if let Some(href) = &props.href {
120            if !should_insert_link(href) {
121                insert_link = false;
122            }
123        }
124
125        if !insert_link {
126            return;
127        }
128
129        document.create_link(props);
130    });
131
132    VNode::empty()
133}
134
135#[derive(Default, Clone)]
136struct LinkContext(DeduplicationContext);
137
138fn should_insert_link(href: &str) -> bool {
139    get_or_insert_root_context::<LinkContext>()
140        .0
141        .should_insert(href)
142}