PageSourceSearch

https://yew.rs/assets/js/7e90a8f1.3257a86e.js

js yew.rs collected 2026-10-03 20:58:54 UTC 10,853 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkyew_docs||=[]).push([[3588],{9459(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>s,metadata:()=>r,toc:()=>a});const r=JSON.parse('{"id":"advanced-topics/children","title":"Children","description":"Inspecting and manipulating Children can often result in surprising and hard-to-explain behaviours in your application.","source":"@site/versioned_docs/version-0.23/advanced-topics/children.mdx","sourceDirName":"advanced-topics","slug":"/advanced-topics/children","permalink":"/docs/advanced-topics/children","draft":false,"unlisted":false,"editUrl":"https://github.com/yewstack/yew/blob/master/website/versioned_docs/version-0.23/advanced-topics/children.mdx","tags":[],"version":"0.23","frontMatter":{"title":"Children"},"sidebar":"docs","previous":{"title":"Refs","permalink":"/docs/advanced-topics/struct-components/refs"},"next":{"title":"Optimizations","permalink":"/docs/advanced-topics/optimizations"}}');var i=t(74848),o=t(28453);const s={title:"Children"},l=void 0,d={},a=[{value:"General usage",id:"general-usage",level:2},{value:"Advanced usage",id:"advanced-usage",level:2},{value:"Typed children",id:"typed-children",level:3},{value:"Nested Children with Props",id:"nested-children-with-props",level:2},{value:"Enum typed children",id:"enum-typed-children",level:3},{value:"Optional typed child",id:"optional-typed-child",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(n.admonition,{type:"caution",children:[(0,i.jsxs)(n.p,{children:["Inspecting and manipulating ",(0,i.jsx)(n.code,{children:"Children"})," can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate ",(0,i.jsx)(n.code,{children:"Children"}),"."]}),(0,i.jsxs)(n.p,{children:["Yew supports using ",(0,i.jsx)(n.code,{children:"Html"})," as the type of the children prop.\nYou should use ",(0,i.jsx)(n.code,{children:"Html"})," as children if you do not need ",(0,i.jsx)(n.code,{children:"Children"})," or ",(0,i.jsx)(n.code,{children:"ChildrenRenderer"}),".\nIt doesn't have the drawbacks of ",(0,i.jsx)(n.code,{children:"Children"})," and has a lower performance overhead."]})]}),"\n",(0,i.jsx)(n.h2,{id:"general-usage",children:"General usage"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.em,{children:"Most of the time,"})," when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class="list">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"advanced-usage",children:"Advanced usage"}),"\n",(0,i.jsx)(n.h3,{id:"typed-children",children:"Typed children"}),"\n",(0,i.jsxs)(n.p,{children:["In cases where you want one type of component to be passed as children to your component,\nyou can use ",(0,i.jsx)(n.code,{children:"yew::html::ChildrenWithProps<T>"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { "item" }\n        }\n    }\n}
1\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class="list">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"nested-children-with-props",children:"Nested Children with Props"}),"\n",(0,i.jsx)(n.p,{children:"Nested component properties can be accessed and mutated if the containing component types its children."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!("item-{}", props.value);\n            item\n    });\n    html! {{for modified_children}}\n}\n\nhtml! {\n    <List>\n        <ListItem value="a" />\n        <ListItem value="b" />\n        <ListItem value="c" />\n    </List>\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"enum-typed-children",children:"Enum typed children"}),"\n",(0,i.jsx)(n.p,{children:"Of course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew."}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.a,{href:"https://github.com/JelteF/derive_more",children:(0,i.jsx)(n.code,{children:"derive_more"})})," crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n",(0,i.jsx)(n.code,{children:"From"})," for each variant."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { "Primary" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { "Secondary" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class="list">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h3,{id:"optional-typed-child",children:"Optional typed child"}),"\n",(0,i.jsx)(n.p,{children:"You can also have a single optional child component of a specific type too:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { "sidebar" }\n        }\n    }\n}
1\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class="page">\n                { ctx.props().sidebar.clone() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the ",(0,i.jsx)(n.a,{href:"https://github.com/yewstack/yew/tree/master/examples/nested_list",children:"nested-list example"})," in the main yew repository."]}),"\n"]})]})}function p(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>l});var r=t(96540);const i={},o=r.createContext(i);function s(e){const n=r.useContext(o);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(o.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.