Pass Components Around as First-Class Values
Contextual Components
The component helper binds a component reference that you can yield, store, or render later — the building block of compound components.
What you'll learn
- Yield a component reference using the component helper
- Render the yielded reference in the parent
- Bind args at the yield site so the parent does less work
A contextual component is a component you pass around as a value. The
component helper takes a name and optional bound args, and returns a
component reference your parent can render. This is how compound components
like tabs, menus, and listboxes are built.
Yielding A Component
{{! app/components/list.hbs }}
<ul>
{{yield (hash
item=(component "list-item")
header=(component "list-header" theme=@theme)
)}}
</ul> The parent destructures and renders:
<List @theme="dark" as |api|>
<api.header>Recent</api.header>
<api.item @text="Apples" />
<api.item @text="Bananas" />
</List> Why Bind Args At The Yield Site
In the example above, theme was bound when list-header was yielded. The
parent never has to know about @theme — it just renders <api.header> and
the theme threads through automatically.
Compound Patterns
This unlocks tightly-coupled APIs without leaking state:
<Tabs as |t|>
<t.list>
<t.tab @id="one">One</t.tab>
<t.tab @id="two">Two</t.tab>
</t.list>
<t.panel @id="one">First panel</t.panel>
<t.panel @id="two">Second panel</t.panel>
</Tabs> Internally, Tabs keeps a @tracked activeId and yields tab / panel
components pre-wired with their selection logic.
Components As Values In JS
You can also store a component reference in JS — useful for dynamic renderers:
import { ensureSafeComponent } from '@embroider/util';
import Avatar from './avatar';
get profileComponent() {
return ensureSafeComponent(Avatar, this);
}