Skip to content

Instantly share code, notes, and snippets.

@runspired
Last active April 21, 2023 17:14
Show Gist options
  • Save runspired/71bc9ee3a6dd0386fb23 to your computer and use it in GitHub Desktop.
Save runspired/71bc9ee3a6dd0386fb23 to your computer and use it in GitHub Desktop.
Some thoughts I had on named yeilds

Ember Named Yields

Current Idea

The current thinking floating around for named yields looks something like this. You can't mix use of named blocks and non-blocked content. Once you use a block helper within a component, everything, including your main yield needs to be within one. If you don't use one, then your yielded content is the main block. This gist is a suggestion I have for how named yields should be implemented and work, and follows the evolution of my thinking on it.

** Only use the primary yield (existing syntax) **

{{#my-component}}
  .. this is the primary (main) yield
{{/my-component}}

** Utilize other named yields in addition to "main" **

{{#my-component}}
  {{#block "main"}}
    .. this is the primary (main) yield
  {{/block}}
  {{#block "secondary"}}
    .. this is a yielded area named secondary
  {{/block}}
{{/my-component}}

Issues with Glimmer Components

The main issue with this syntax is that it doesn't mix elegantly with Glimmer Components because of the alternating use of {{ and <.

<my-component>
  {{#block "main"}}

  {{/block}}
  {{#block "secondary"}}

  {{/block}}
</my-component>

Contextual Components

We could go with an approach that looks more like contextual components where blocks are part of the yield.

<my-component as |foo|>
 <foo.blocks.main></foo.blocks.main>
 <foo.blocks.secondary></foo.blocks.secondary>
</my-component>

But directly relying on the contextual component implementation for this introduces potentially complicated/mistake-prone/incompatible wiring by the component's creator.

Differentiate Named Yields from Contextual Components

We could differentiate from named yields by auto-yielding a special blocks keyword.

<my-component as |foo|>
  <blocks.main> <!-- named yield -->
    <foo.input-button> <!-- contextual component -->
  </blocks.main>
  <blocks.secondary></blocks.secondary>
</my-component>

Dealing with block params

The issue with our new block helpers is that you probably want to yield different content to different blocks. For instance, let's say this is how you write the component's template for my-component.

{{block "main" ...blockParamsA}}
{{block "secondary" ...blockParamsB}}

In our current syntax this would lead to foo having a different value in each block, which is unintuitive and not very ergonomic.

So let's follow the same guidlines as we did when we decided that "if you use the block helper, you must wrap all content within one, even the main yield". When you use the block helper, you don't yield your block params on the component. Here's what I mean.

<my-component as |foo|>
  <!-- "main" block with yielded foo-->
</my-component>

<my-component>
  <blocks.main as |foo|> 
    <!-- "main" block with yielded foo-->
  </blocks.main>
  <blocks.secondary as |bar|>
    <!-- "secondary" block with yielded bar -->
  </blocks.secondary>
</my-component>
@runspired
Copy link
Author

for legacy:

{{#my-component as |foo|}}
  <!-- "main" block with yielded foo-->
{{/my-component}}

{{#my-component}}
  {{#block 'main' as |foo|}}
    <!-- "main" block with yielded foo-->
  {{/block}}
  {{#block 'secondary' as |bar|>
    <!-- "secondary" block with yielded bar -->
  {{/block}}
{{/my-component}}

I actually think this might be attainable in Ember currently all the way back to 1.11/1.12.

For 2.3+ we'd rely on contextual components. For < 2.3 we'd either polyfill contextual components or implement it with the render helper and special template=>partials compilation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment