Children

General usage

Most of the time, when allowing a component to have children, you don’t care what type of children the component has. In such cases, the below example will suffice.

  1. use yew::{html, Children, Component, Context, Html, Properties};
  2. #[derive(Properties, PartialEq)]
  3. pub struct ListProps {
  4. #[prop_or_default]
  5. pub children: Children,
  6. }
  7. pub struct List;
  8. impl Component for List {
  9. type Message = ();
  10. type Properties = ListProps;
  11. fn create(_ctx: &Context<Self>) -> Self {
  12. Self
  13. }
  14. fn view(&self, ctx: &Context<Self>) -> Html {
  15. html! {
  16. <div class="list">
  17. { for ctx.props().children.iter() }
  18. </div>
  19. }
  20. }
  21. }

Advanced usage

Typed children

In cases where you want one type of component to be passed as children to your component, you can use yew::html::ChildrenWithProps<T>.

  1. use yew::{html, ChildrenWithProps, Component, Context, Html, Properties};
  2. pub struct Item;
  3. impl Component for Item {
  4. type Message = ();
  5. type Properties = ();
  6. fn create(_ctx: &Context<Self>) -> Self {
  7. Self
  8. }
  9. fn view(&self, _ctx: &Context<Self>) -> Html {
  10. html! {
  11. { "item" }
  12. }
  13. }
  14. }
  15. #[derive(Properties, PartialEq)]
  16. pub struct ListProps {
  17. #[prop_or_default]
  18. pub children: ChildrenWithProps<Item>,
  19. }
  20. pub struct List;
  21. impl Component for List {
  22. type Message = ();
  23. type Properties = ListProps;
  24. fn create(_ctx: &Context<Self>) -> Self {
  25. Self
  26. }
  27. fn view(&self, ctx: &Context<Self>) -> Html {
  28. html! {
  29. <div class="list">
  30. { for ctx.props().children.iter() }
  31. </div>
  32. }
  33. }
  34. }

Enum typed children

Of course, sometimes you might need to restrict the children to a few different components. In these cases, you have to get a little more hands-on with Yew.

The derive_more crate is used here for better ergonomics. If you don’t want to use it, you can manually implement From for each variant.

  1. use yew::{
  2. html, html::ChildrenRenderer, virtual_dom::VChild, Component,
  3. Context, Html, Properties,
  4. };
  5. pub struct Primary;
  6. impl Component for Primary {
  7. type Message = ();
  8. type Properties = ();
  9. fn create(_ctx: &Context<Self>) -> Self {
  10. Self
  11. }
  12. fn view(&self, _ctx: &Context<Self>) -> Html {
  13. html! {
  14. { "Primary" }
  15. }
  16. }
  17. }
  18. pub struct Secondary;
  19. impl Component for Secondary {
  20. type Message = ();
  21. type Properties = ();
  22. fn create(_ctx: &Context<Self>) -> Self {
  23. Self
  24. }
  25. fn view(&self, _ctx: &Context<Self>) -> Html {
  26. html! {
  27. { "Secondary" }
  28. }
  29. }
  30. }
  31. #[derive(Clone, derive_more::From, PartialEq)]
  32. pub enum Item {
  33. Primary(VChild<Primary>),
  34. Secondary(VChild<Secondary>),
  35. }
  36. // Now, we implement `Into<Html>` so that yew knows how to render `Item`.
  37. #[allow(clippy::from_over_into)]
  38. impl Into<Html> for Item {
  39. fn into(self) -> Html {
  40. match self {
  41. Self::Primary(child) => child.into(),
  42. Self::Secondary(child) => child.into(),
  43. }
  44. }
  45. }
  46. #[derive(Properties, PartialEq)]
  47. pub struct ListProps {
  48. #[prop_or_default]
  49. pub children: ChildrenRenderer<Item>,
  50. }
  51. pub struct List;
  52. impl Component for List {
  53. type Message = ();
  54. type Properties = ListProps;
  55. fn create(_ctx: &Context<Self>) -> Self {
  56. Self
  57. }
  58. fn view(&self, ctx: &Context<Self>) -> Html {
  59. html! {
  60. <div class="list">
  61. { for ctx.props().children.iter() }
  62. </div>
  63. }
  64. }
  65. }

Optional typed child

You can also have a single optional child component of a specific type too:

  1. use yew::{
  2. html, html_nested, virtual_dom::VChild, Component,
  3. Context, Html, Properties
  4. };
  5. pub struct PageSideBar;
  6. impl Component for PageSideBar {
  7. type Message = ();
  8. type Properties = ();
  9. fn create(_ctx: &Context<Self>) -> Self {
  10. Self
  11. }
  12. fn view(&self, _ctx: &Context<Self>) -> Html {
  13. html! {
  14. { "sidebar" }
  15. }
  16. }
  17. }
  18. #[derive(Properties, PartialEq)]
  19. pub struct PageProps {
  20. #[prop_or_default]
  21. pub sidebar: Option<VChild<PageSideBar>>,
  22. }
  23. struct Page;
  24. impl Component for Page {
  25. type Message = ();
  26. type Properties = PageProps;
  27. fn create(_ctx: &Context<Self>) -> Self {
  28. Self
  29. }
  30. fn view(&self, ctx: &Context<Self>) -> Html {
  31. html! {
  32. <div class="page">
  33. { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }
  34. // ... page content
  35. </div>
  36. }
  37. }
  38. }
  39. // The page component can be called either with the sidebar or without:
  40. pub fn render_page(with_sidebar: bool) -> Html {
  41. if with_sidebar {
  42. // Page with sidebar
  43. html! {
  44. <Page sidebar={html_nested! {
  45. <PageSideBar />
  46. }} />
  47. }
  48. } else {
  49. // Page without sidebar
  50. html! {
  51. <Page />
  52. }
  53. }
  54. }