11ty / webc

Single File Web Components
MIT License
1.3k stars 36 forks source link

Nesting Question #183

Closed sc0ttes closed 1 year ago

sc0ttes commented 1 year ago

Hi all, relatively new to webc and have a question regarding nested webc components. I am hoping to do a layout roughly as so but cant seem to get it to work or don't understand the correct design pattern:

templates/mytemplate.webc

---
layout: layout.webc
---
<header></header>
<one_column>
  <span>First</span>
  <span>Second</span>
  <span>Third</span>
</one_column>
<footer></footer>

_includes/layout.webc

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>My Website</title>
  </head>
  <body>
    <div @html="content" class="one"></div>
  </body>
</html>

_includes/webc/layout_parts/one_column.webc

<div class="two">
  <div class="three">
    <div @html="content" class="four"></div>
  </div>
</div>

Where I seem to be stuck is if it's possible to grab the innerHTML from <one_column> (the three spans) and inject them into the innermost div in the one_column.webc layout part before it gets rolled up into the layout.webc file along with the header and footer.

The output I'm looking for would look roughly like:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>My Website</title>
  </head>
  <body>
    <div class="one">
      [whatever was in the header component]
      <div class="two">
        <div class="three">
          <div class="four">
            <span>First</span>
            <span>Second</span>
            <span>Third</span>
          </div>
        </div>
      </div>
      [whatever was in the footer component]
    </div>
  </body>
</html>

I am hoping to eventually replace those <span>s with other webc components and wrap them with additional tidbits in a webc:for loop but cant seem to get the basic span example working.

Thanks for any help!

sc0ttes commented 1 year ago

Well I found one way of doing it that isn't as clean but seems to work: putting the <span>s in an string or array and passing them direct or to a webc:for loop. I figured this would work as it's basically as documented. This also seems to work with putting custom webc components in the string/array.

templates/mytemplate.webc

---
layout: layout.webc
---
<header></header>
<one_column :column-content="['<span>First</span>', '<span>Second</span>', '<span>Third</span>']">
</one_column>
<footer></footer>

_includes/layout.webc

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>My Website</title>
  </head>
  <body>
    <div @html="content" class="one"></div>
  </body>
</html>

_includes/webc/layout_parts/one_column.webc

<div class="two">
  <div class="three">
    <div webc:for="item in columnContents" @html="item" class="four"></div>
  </div>
</div>

Would be nice if possible to take the inner content of a parent declared webc component and pass it along for use in the actual component itself so that templating and markup would still look good. Definitely still interested if anyone knows a way to do that easily.

sc0ttes commented 1 year ago

After rereading the documentation, I realized slots are precisely what I was looking for. Using code from the example in the subscription-form.webc example from here worked well for me. I used a slot to insert the 3 spans and then used some client-side JavaScript to capture the inserted spans and wrap them in additional code.

I'm still trying to figure out if there's a way to do that client-side bit of JS on the server side (custom transforms look promising albeit possibly convoluted) but I feel much closer to a complete solution now than before. Feel free to close this issue if there are no additional comments to be made.

dspint commented 1 year ago

Piggybacking, it looks like there are issues with nested components and slots. Example:

content-width.webc

<content-width @attributes webc:root="override">
  <slot></slot>
</content-width>

custom-section.webc

<section @attributes webc:root="override">
  <zc-content-width>
    <slot></slot>
  </zc-content-width>
</section>

index.html

---
title: 'Test'
---
<custom-section>
  Test
</custom-section>

Looks like there's some kind of circular things going on and causes the dev server to timeout. Is this a bug or are nested components w/ slots not supported? For comparison, nested components do work as long as you are not slotting in content 'from lightdom'.

Fyi, adding named slots didn't make a difference:

content-width.webc

<content-width @attributes webc:root="override">
  <slot name="content"></slot>
</content-width>

custom-section.webc

<section @attributes webc:root="override">
  <zc-content-width>
    <slot name="content"></slot>
  </zc-content-width>
</section>

index.html

---
title: 'Test'
---
<custom-section>
  <h1 slot="content">Test</h1>
</custom-section>
dspint commented 1 year ago

It looks like this works, where both components have a default <slot>:

index.html

<custom-section>
  <content-width>
    Test
  </content-width>
</custom-section>

Just a bummer you have to manually add <content-width> each instance of <custom-section> instead of it already being in <custom-sections>'s component code.

sc0ttes commented 1 year ago

Hey @dspint,

Unless I'm mistaken, the custom webc component tag names are coming from the file names so you'd want to rename content-width.webc to zc-content-width.webc and things may be working better?

sc0ttes commented 1 year ago

I am running into similar nested slot issues though where using webc:root="override" or @attributes in a component seems to remove the [default or named] slot within it

sc0ttes commented 1 year ago

I've found my issue in particular is a HTML table tag slot issue. Having <table><slot></slot></table> with the <tr><td> [some content] </td></tr> tags in the slot content, seems to push all of the slot content outside and before the table leaving the table empty. If I'm able to figure out where in particular the bug is, I'll make a new issue and PR to fix if easy.

In the meantime, it seems a workaround is doing <table><tr><td><slot></slot></td></tr></table> though then I can't style the <td> where the slot content is without adding webc vars.

sc0ttes commented 1 year ago

After quite a bit of poking around the src/ folder, I can't seem to find where the tr and td tags get dropped when putting default slot content into the final output. That said, it's definitely a bug.

sc0ttes commented 1 year ago

I've resolved both of my issues I was looking for help with through the use of slots and webc:is