1"use strict";(globalThis.webpackChunkyew_docs||=[]).push([[18],{55530(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>c,default:()=>p,frontMatter:()=>o,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"concepts/html/introduction","title":"HTML","description":"The procedural macro for generating HTML and SVG","source":"@site/docs/concepts/html/introduction.mdx","sourceDirName":"concepts/html","slug":"/concepts/html","permalink":"/docs/next/concepts/html","draft":false,"unlisted":false,"editUrl":"https://github.com/yewstack/yew/blob/master/website/docs/concepts/html/introduction.mdx","tags":[],"version":"current","frontMatter":{"title":"HTML","sidebar_label":"Introduction","description":"The procedural macro for generating HTML and SVG","slug":"/concepts/html"},"sidebar":"docs","previous":{"title":"Generic Components","permalink":"/docs/next/concepts/function-components/generics"},"next":{"title":"Components","permalink":"/docs/next/concepts/html/components"}}');var s=t(74848),i=t(28453),l=t(4865),a=t(19365);const o={title:"HTML",sidebar_label:"Introduction",description:"The procedural macro for generating HTML and SVG",slug:"/concepts/html"},c=void 0,d={},u=[{value:"Tag Structure",id:"tag-structure",level:2},{value:"Children",id:"children",level:2},{value:"Lints",id:"lints",level:2},{value:"Specifying attributes and properties",id:"specifying-attributes-and-properties",level:2},{value:"Special properties",id:"special-properties",level:3},{value:"Comments",id:"comments",level:2},{value:"Conditional Rendering",id:"conditional-rendering",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"html!"})," macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript that allows you to write HTML-like code inside of JavaScript)."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.strong,{children:"Important notes"})}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"html!"})," macro accepts any number of root nodes. An empty ",(0,s.jsx)(n.code,{children:"html! {}"})," invocation will not render anything."]}),"\n",(0,s.jsxs)(n.li,{children:["String literals need to be quoted and usually needs to be wrapped in braces: ",(0,s.jsx)(n.code,{children:'html! { <p>{ "Hello, World" }</p> }'}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Bool types and number types can be used directly: ",(0,s.jsx)(n.code,{children:"html!{ <span>{1}</span> <span>{true}</span> }"})]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"html!"})," macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like ",(0,s.jsx)(n.code,{children:'#![recursion_limit="1024"]'})," in the crate root to overcome the problem."]})}),"\n",(0,s.jsx)(n.h2,{id:"tag-structure",children:"Tag Structure"}),"\n",(0,s.jsx)(n.p,{children:"Tags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax."}),"\n",(0,s.jsxs)(n.p,{children:["Tags must either self-close ",(0,s.jsx)(n.code,{children:"<... />"})," or have a corresponding end tag for each start tag."]}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(a.A,{value:"Open - Close",label:"Open - Close",default:!0,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n <div id="my_div"></div>\n};\n'})})}),(0,s.jsx)(a.A,{value:"Invalid",label:"Invalid",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",metastring:",compile_fail",children:'use yew::prelude::*;\n\nhtml! {\n <div id="my_div"> // <- MISSING CLOSE TAG\n};\n'})})})]}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(a.A,{value:"Self-closing",label:"Self-closing",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n <input id="my_input" />\n};\n'})})}),(0,s.jsx)(a.A,{value:"Invalid",label:"Invalid",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",metastring:",compile_fail",children:'use yew::prelude::*;\n\nhtml! {\n <input id="my_input"> // <- MISSING SELF-CLOSE\n};\n'})})})]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["For convenience, elements which ",(0,s.jsx)(n.em,{children:"usually"})," require a closing tag are ",(0,s.jsx)(n.strong,{children:"allowed"})," to self-close. For example, writing ",(0,s.jsx)(n.code,{children:'html! { <div class="placeholder" /> }'})," is valid."]})}),"\n",(0,s.jsx)(n.h2,{id:"children",children:"Children"}),"\n",(0,s.jsx)(n.p,{children:"Create complex nested HTML and SVG layouts with ease:"}),"\n",(0,s.jsxs)(l.A,{children:[(0,s.jsx)(a.A,{value:"HTML",label:"HTML",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n <div>\n <div data-key="abc"></div>\n <div class="parent">
1\n <span class="child" value="anything"></span>\n <label for="first-name">{ "First Name" }</label>\n <input type="text" id="first-name" value="placeholder" />\n <input type="checkbox" checked=true />\n <textarea value="write a story" />\n <select name="status">\n <option selected=true disabled=false value="">{ "Selected" }</option>\n <option selected=false disabled=true value="">{ "Unselected" }</option>\n </select>\n </div>\n </div>\n};\n'})})}),(0,s.jsx)(a.A,{value:"SVG",label:"SVG",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n <svg width="149" height="147" viewBox="0 0 149 147" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z" fill="#DEB819"/>\n <path d="M108.361 94.9937L138.708 90.686L115.342 69.8642" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>\n <g filter="url(#filter0_d)">\n <circle cx="75.3326" cy="73.4918" r="55" fill="#FDD630"/>\n <circle cx="75.3326" cy="73.4918" r="52.5" stroke="black" stroke-width="5"/>\n </g>\n <circle cx="71" cy="99" r="5" fill="white" fill-opacity="0.75" stroke="black" stroke-width="3"/>\n <defs>\n <filter id="filter0_d" x="16.3326" y="18.4918" width="118" height="118" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">\n <@{"feGaussianBlur"} stdDeviation="2"/>\n <@{"feColorMatrix"} in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>\n </filter>\n </defs>\n </svg>\n};\n'})})})]}),"\n",(0,s.jsx)(n.h2,{id:"lints",children:"Lints"}),"\n",(0,s.jsxs)(n.p,{children:["If you compile Yew using a nightly version of the Rust compiler, the macro will warn
1you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running ",(0,s.jsx)(n.code,{children:"cargo +nightly check"})," might flag some ways that you could improve your\nHTML code."]}),"\n",(0,s.jsxs)(n.p,{children:["At the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to ",(0,s.jsx)(n.a,{href:"https://github.com/yewstack/yew/issues/1334",children:"chime in on this issue"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"specifying-attributes-and-properties",children:"Specifying attributes and properties"}),"\n",(0,s.jsx)(n.p,{children:"Attributes are set on elements in the same way as in normal HTML:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nlet value = "something";\nhtml! { <div attribute={value} /> };\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Properties are specified with ",(0,s.jsx)(n.code,{children:"~"})," before the element name:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",metastring:", ignore",children:'use yew::prelude::*;\n\nhtml! { <my-element ~property="abc" /> };\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsx)(n.p,{children:"The braces around the value can be omitted if the value is a literal."})}),"\n",(0,s.jsx)(n.admonition,{title:"What classifies as a literal",type:"note",children:(0,s.jsxs)(n.p,{children:["Literals are all valid ",(0,s.jsx)(n.a,{href:"https://doc.rust-lang.org/reference/expressions/literal-expr.html",children:"literal expressions"}),"\nin Rust. Note that ",(0,s.jsxs)(n.a,{href:"https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333",children:["negative numbers are ",(0,s.jsx)(n.strong,{children:"not"})," literals"]}),"\nand thus must be enclosed in curly-braces ",(0,s.jsx)(n.code,{children:"{-6}"})]})}),"\n",(0,s.jsxs)(n.p,{children:["Attribute names can also be set dynamically using string literals or expressions. This is useful for\nattributes that are not valid Rust identifiers, such as ",(0,s.jsx)(n.code,{children:"hx-on:click"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! { <div "hx-on:click"="alert(\'Clicked!\')" /> };\nhtml! { <div { String::from("hx-on:click") }={ "alert(\'Clicked!\')" } /> };\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Read more at ",(0,s.jsx)(n.a,{href:"./html/elements#dynamic-attribute-names",children:"Dynamic attribute names"})]})}),"\n",(0,s.jsx)(n.admonition,{title:"Component properties",type:"note",children:(0,s.jsxs)(n.p,{children:["Component properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at ",(0,s.jsx)(n.a,{href:"/docs/next/concepts/function-components/properties",children:"Component Properties"})]})}),"\n",(0,s.jsx)(n.h3,{id:"special-properties",children:"Special properties"}),"\n",(0,s.jsxs)(n.p,{children:["There are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: ",(0,s.jsx)(n.code,{children:"ref"})," and ",(0,s.jsx)(n.code,{children:"key"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"ref"})," allows you to access and manipulate the underlying DOM node directly. See ",(0,s.jsx)(n.a,{href:"/docs/next/concepts/function-components/node-refs",children:"Refs"})," for more details."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"key"})," on the other hand gives an element a unique identifier which Yew can use for optimization purposes."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Read more at ",(0,s.jsx)(n.a,{href:"./html/lists",children:"Lists"})]})}),"\n",(0,s.jsx)(n.h2,{id:"comments",children:"Comments"}),"\n",(0,s.jsx)(n.p,{children:"It is also possible to use Rust style comments as part of the HTML structure:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n <h1>{ "My heading" }</h1>\n // here comes the content\n <main>\n { "\u2026" }\n </main>\n};\n'})}),"\n",(0,s.jsx)(n.p,{children:"Comments will be dropped during the parsing process and will not end up in the final output."}),"\n",(0,s.jsx)(n.h2,{id:"conditional-rendering",children:"Conditional Rendering"}),"\n",(0,s.jsxs)(n.p,{children:["Markup can be rendered conditionally by using Rust's ",(0,s.jsx)(n.code,{children:"if"}),", ",(0,s.jsx)(n.code,{children:"if let"}),", and ",(0,s.jsx)(n.code,{children:"match"})," expressions directly inside ",(0,s.jsx)(n.code,{children:"html!"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-rust",children:'use yew::prelude::*;\n\nhtml! {\n if true {\n <p>{ "True case" }</p>\n }\n};\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Read more at ",(0,s.jsx)(n.a,{href:"/docs/next/concepts/html/conditional-rendering",children:"Conditional Rendering"})]})})]})}function p(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},19365(e,n,t){t.d(n,{A:()=>o});t(96540);var r=t(34164),s=t(47751);const i="tabItem_Ymn6";var l=t(74848);function a({children:e,className:n,hidden:t}){return(0,l.jsx)("div",{role:"tabpanel",className:(0,r.A)(i,n),hidden:t,children:e})}function o({children:e,className:n,value:t}){const{selectedValue:r,lazy:i}=(0,s.uc)(),o=t===r;return!o&&i?null:(0,l.jsx)(a,{className:n,hidden:!o,children:e})}},4865(e,n,t){t.d(n,{A:()=>m});t(96540);var r=t(34164),s=t(17559),i=t(47751),l=t(23104),a=t(92303);const o="tabList__CuJ",c="tabItem_LNqP";var d=t(74848);function u({className:e}){const{selectedValue:n,selectValue:t,tabValues:s,block:a}=(0,i.uc)(),o=[],{blockElementScrollPositionUntilNextRender:u}
1=(0,l.a_)(),h=e=>{const r=e.currentTarget,i=o.indexOf(r),l=s[i].value;l!==n&&(u(r),t(l))},p=e=>{let n=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{const t=o.indexOf(e.currentTarget)+1;n=o[t]??o[0];break}case"ArrowLeft":{const t=o.indexOf(e.currentTarget)-1;n=o[t]??o[o.length-1];break}}n?.focus()};return(0,d.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":a},e),children:s.map(({value:e,label:t,attributes:s})=>(0,d.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{o.push(e)},onKeyDown:p,onClick:h,...s,className:(0,r.A)("tabs__item",c,s?.className,{"tabs__item--active":n===e}),children:t??e},e))})}function h({children:e}){return(0,d.jsx)("div",{className:"margin-top--md",children:e})}function p({className:e,children:n}){return(0,d.jsxs)("div",{className:(0,r.A)(s.G.tabs.container,"tabs-container",o),children:[(0,d.jsx)(u,{className:e}),(0,d.jsx)(h,{children:n})]})}function m(e){const n=(0,a.A)(),t=(0,i.OC)(e);return(0,d.jsx)(i.O_,{value:t,children:(0,d.jsx)(p,{className:e.className,children:(0,i.vT)(e.children)})},String(n))}},47751(e,n,t){t.d(n,{OC:()=>m,O_:()=>g,uc:()=>f,vT:()=>d});var r=t(96540),s=t(56347),i=t(205),l=t(57485),a=t(70679),o=t(31682),c=t(74848);function d(e){return r.Children.toArray(e).filter(e=>"\n"!==e)}function u(e){const{values:n,children:t}=e;return(0,r.useMemo)(()=>{const e=n??function(e){return r.Children.toArray(e).flatMap(e=>{if(!e)return[];if((0,r.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return[e];const n="string"==typeof e.type?e.type:e.type.name;throw new Error(`Docusaurus error: Bad <Tabs> child <${n}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.\nIf you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:n,attributes:t,default:r}})=>({value:e,label:n,attributes:t,default:r}))}(t);return function(e){const n=(0,o.XI)(e,(e,n)=>e.value===n.value);if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e},[n,t])}function h({value:e,tabValues:n}){return n.some(n=>n.value===e)}function p({queryString:e=!1,groupId:n}){const t=(0,s.W6)(),i=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,l.aZ)(i),(0,r.useCallback)(e=>{if(!i)return;const n=new URLSearchParams(t.location.search);n.set(i,e),t.replace({...t.location,search:n.toString()})},[i,t])]}function m(e){const{defaultValue:n,queryString:t=!1,groupId:s}=e,l=u(e),[o,c]=(0,r.useState)(()=>function({defaultValue:e,tabValues:n}){if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!h({value:e,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}const t=n.find(e=>e.default)??n[0];if(!t)throw new Error("Unexpected error: 0 tabValues");return t.value}({defaultValue:n,tabValues:l})),[d,m]=p({queryString:t,groupId:s}),[x,f]=function({groupId:e}){const n=function(e){return e?`docusaurus.tab.${e}`:null}(e),[t,s]=(0,a.Dv)(n);return[t,(0,r.useCallback)(e=>{n&&s.set(e)},[n,s])]}({groupId:s}),g=(()=>{const e=d??x;return h({value:e,tabValues:l})?e:null})();(0,i.A)(()=>{g&&c(g)},[g]);return{selectedValue:o,selectValue:(0,r.useCallback)(e=>{if(!h({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);c(e),m(e),f(e)},[m,f,l]),tabValues:l,lazy:e.lazy??!1,block:e.block??!1}}const x=(0,r.createContext)(null);function f(){const e=r.useContext(x);if(!e)throw new Error("useTabsContext() must be used within a Tabs component");return e}function g(e){return(0,c.jsx)(x.Provider,{value:e.value,children:e.children})}},28453(e,n,t){t.d(n,{R:()=>l,x:()=>a});var r=t(96540);const s={},i=r.createContext(s);function l(e){const n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.