dioxus_document/elements/
link.rs

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