QwikDev / qwik

Instant-loading web apps, without effort
https://qwik.dev
MIT License
20.46k stars 1.26k forks source link

[✨] Enable the attribute q:slot on Fragment #4894

Open phcoliveira opened 11 months ago

phcoliveira commented 11 months ago

Is your feature request related to a problem?

Yes, so to say.

When you use the default slot, it is possible to pass only text. And this is very useful if you want to ensure such copy should aways look the same. Like in:

const Button = component$(() => {
  return (
    <button>
      <Slot />
    </button>
  );
});

However, it is not possible to do so when using named slots because you need an HTML Element onto which the attribute q:slot is attached.

const Post = component$(() => {
  return (
    <article>
      <h1><Slot name="title" /></h1>

      <main>
        <Slot />
      </main>
    </article>
  );
});

The consumer of Post, when passing content to the named slot title, needs to do it with an element. Possibly a span, but an inconvenience nonetheless.

Describe the solution you'd like

I would like that the Fragment component could accept the q:slot attribute. That way, considering the component Post, from above, it would be possible to pass only text to the title.

const Page = component$(() => {
  return (
    <Post>
      <Fragment q:slot="title">Just text</Fragment>
      <p>Lorem ipsum bla bla bla...</p>
    </Post>
  );
});

Describe alternatives you've considered

I have been using "harmless" elements, like span, to pass text to named slots. But it is not a perfect solution.

Additional context

I created a discussion about it on Discord.

https://discord.com/channels/842438759945601056/1134954295897358417

eduardvercaemer commented 7 months ago

Something similar occurs when one wants to project multiple items into the same Slot.

Currently I have to do:

export default component$(() => {
  return (
    <ResponsiveSidebar>
      <li q:slot="item">
        <a>hello</a>
      </li>
      <li q:slot="item">
        <a>hello</a>
      </li>
      <li q:slot="item">
        <a>hello</a>
      </li>

      <Slot />
    </ResponsiveSidebar>
  );
});

and I believe wrapping them in a fragment to reuse the slot name would be helpful:

export default component$(() => {
  return (
    <ResponsiveSidebar>
      <q:slot="item">
        <li>
          <a>hello</a>
        </li>
        <li>
          <a>hello</a>
        </li>
        <li>
          <a>hello</a>
        </li>
      </>

      <Slot />
    </ResponsiveSidebar>
  );
});