# Body content We're used to passing body content to HTML tags. When you do this, the tag has control over where and when this content is rendered. A good example of this is the [HTML `
` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details): ```html
Hello World This is some content that can be toggled.
``` This is what it renders (try clicking it): ---
Hello World This is some content that can be toggled.
--- Custom tags can also receive content in the same way. This allows a component to give its user full control over _how_ some section of the content is rendered, but control _where_, _when_, and with _what_ data it is rendered. This feature is necessary to build composable components like overlays, layouts, dropdowns, etc. Imagine a `` that didn't give you control over how its cells were rendered. That would be pretty limited! ## Rendering body content When a custom tag is passed body content, it is received as a special `renderBody` property on the component's `input`. You can include this content anywhere in your component by using the [`<${dynamic}>` syntax](./syntax.md#dynamic-tagname). _components/fancy-container.marko:_ ```marko
<${input.renderBody}/>
``` If we were to use this tag like this: _Marko Source:_ ```marko

Content goes here...

``` The rendered output would be: _HTML Output:_ ```html

Content goes here...

``` This is a pretty basic example, but you can imagine how this could be incorporated into a more advanced component to render passed content where/when needed. > **ProTip:** > Body content can be rendered multiple times. Or not at all. ## Passing attributes to body content When rendering body content with `<${dynamic}>`, attributes may also be passed: _components/random-value.marko:_ ```marko <${input.renderBody} number=1337 /> ``` These attribute values can be received as a [tag parameter](./syntax.md#parameters): ```marko The number is ${number} ``` > **ProTip:** > Some tags (like the above tag) may not render anything except their body content with some data. This can be quite useful, just look at the `` and `` tags! ## Named body content You can also pass named content sections to a tag using [attribute tags](./syntax.md#attribute-tag) which are denoted by the `@` prefix. ```marko <@heading>

Hello Marko

<@content>

...

``` Like attributes, these attribute tags are received as `input.heading` and `input.content`, but they each have a `renderBody` property which we can now use: _components/layout.marko_ ```marko <${input.heading.renderBody}/>
<${input.content.renderBody}/> ``` > **ProTip:** The `renderBody` property can be omitted. You could use `<${input.heading}/>`, for example. ### Repeated body content When an attribute tag is repeated, the child component can consume all instances using the [iterable protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol). This allows us to, for example, build a custom table component which allows its user to specify any number of columns, while still giving the user control over how each column is rendered. _Marko Source:_ ```marko <@column|person|> Name: ${person.name} <@column|person|> Age: ${person.age} ``` > _Note_ > For TypeScript the [`Marko.AttrTag` helper](./typescript.md#built-in-marko-types) should be used here. > _Protip_ > Since attribute tags are iterable you could pass `input.column` to a `for of` loop, or `[...spread]` it into an array. > To `.map`, `.filter` or otherwise work with attribute tags as an array you can use the following pattern: > > ```marko > $ const columns = [...input.column || []]; > ``` We can then use the `` tag to render the body content into table, passing the row data to each column's body. _components/fancy-table/index.marko:_ ```marko {4-8}
<${column.renderBody} ...row/>
``` We now have a working ``. Let's see what it renders: _Example Data:_ ```js [ { name: "Patrick", age: 63, }, { name: "Austin", age: 12, }, ]; ``` _HTML Output:_ ```html
Name: Patrick Age: 63
Name: Austin Age: 12
``` ### Attributes on attribute tags If you look at our previous example, we had to prefix each cell with the column label. It would be better if we could give a name to each column instead and only render that once. _Marko Source:_ ```marko <@column|person| heading="Name"> ${person.name} <@column|person| heading="Age"> ${person.age} ``` Now, each attribute tag in `input.column` will contain a `heading` property in addition to its `renderBody`. We can use another `` and render the headings in `` tags: _components/fancy-table/index.marko:_ ```marko {3-5}
${column.heading}
<${column.renderBody} ...row/>
``` We'll now get a row of headings when we render our `` _HTML Output:_ ```html
Name Age
Patrick 63
Austin 12
``` ### Nested attribute tags Continuing to build on our example, what if we want to add some custom content or even components into the column headings? In this case, we can extend our `` to use nested attribute tags. We'll now have `<@heading>` and `<@cell>` tags nested under `<@column>`. This gives users of our tag full control over how to render both column headings and the cells within the column! _Marko Source:_ ```marko {3-8} <@column> <@heading> Name <@cell|person|> ${person.name} <@column> <@heading> Age <@cell|person|> ${person.age} ``` Now instead of rendering the heading as text, we'll render the heading's body content. _components/fancy-table/index.marko:_ ```marko {5}
<${column.heading.renderBody}/>
<${column.cell.renderBody} ...row/>
``` Our headings can now include icons (and anything else)! _HTML Output:_ ```html
Name Age
Patrick 63
Austin 12
``` ### Dynamic attribute tags The flexibility of the `` is great if you want to render columns differently or have columns that display the data in a special way (such as displaying an age derived from a date of birth). However, if all columns are basically the same, the user might feel they're repeating themselves. As you might expect, you can use `` (and ``) to dynamically render attribute tags. ```marko $ const columns = [{ property: "name", title: "Name", icon: "profile" }, { property: "age", title: "Age", icon: "calendar" }] <@column> <@heading> ${title} <@cell|person|> ${person[property]} ```