terracotta icon indicating copy to clipboard operation
terracotta copied to clipboard

Missing `Tab.Panels` component

Open oscartbeaumont opened this issue 2 years ago • 3 comments

I have been loving this library but I could not find an alternative to Table.Panels. Does one exist that I am just missing or is this something that has not yet been added to the libray?

oscartbeaumont avatar Sep 22 '22 16:09 oscartbeaumont

I'm not sure which one are you referring to, Tabs or Tables? if Tabs, TabPanels isn't created since it has no purpose, so users can implement their own grouping element.

lxsmnsyc avatar Sep 23 '22 00:09 lxsmnsyc

I was referring to Tab.Panels. I am converting some TailwindUI components to SolidJS and they make use of it.

Are you certain that Tab.Panels does nothing? When I use a div in place of it all of the 4 panels I define are shown at the same time instead of it just showing the active panel.

Component code - using `Tab.Panels` to show clearly where I am using it
 <TabGroup
    as="div"
    className="mt-16 grid grid-cols-1 items-center gap-y-2 pt-10 sm:gap-y-6 md:mt-20 lg:grid-cols-12 lg:pt-0"
    vertical={tabOrientation === "vertical"}
>
    {({ selectedIndex }) => (
    <>
        <div className="-mx-4 flex overflow-x-auto pb-4 sm:mx-0 sm:overflow-visible sm:pb-0 lg:col-span-5">
        <TabList className="relative z-10 flex gap-x-4 whitespace-nowrap px-4 sm:mx-auto sm:px-0 lg:mx-0 lg:block lg:gap-x-0 lg:gap-y-1 lg:whitespace-normal">
            {features.map((feature, featureIndex) => (
            <div
                key={feature.title}
                className={clsx(
                "group relative rounded-full py-1 px-4 lg:rounded-r-none lg:rounded-l-xl lg:p-6",
                selectedIndex === featureIndex
                    ? "bg-white lg:bg-white/10 lg:ring-1 lg:ring-inset lg:ring-white/10"
                    : "hover:bg-white/10 lg:hover:bg-white/5"
                )}
            >
                <h3>
                <Tab
                    className={clsx(
                    "font-display text-lg [&:not(:focus-visible)]:focus:outline-none",
                    selectedIndex === featureIndex
                        ? "text-blue-600 lg:text-white"
                        : "text-blue-100 hover:text-white lg:text-white"
                    )}
                >
                    <span className="absolute inset-0 rounded-full lg:rounded-r-none lg:rounded-l-xl" />
                    {feature.title}
                </Tab>
                </h3>
                <p
                className={clsx(
                    "mt-2 hidden text-sm lg:block",
                    selectedIndex === featureIndex
                    ? "text-white"
                    : "text-blue-100 group-hover:text-white"
                )}
                >
                {feature.description}
                </p>
            </div>
            ))}
        </TabList>
        </div>
        <TabPanels className="lg:col-span-7">
        {features.map((feature, featureIndex) => (
            <TabPanel key={feature.title} unmount={false}>
            <div className={"relative sm:px-6 lg:hidden"}>
                <div className="absolute -inset-x-4 top-[-6.5rem] bottom-[-4.25rem] bg-white/10 ring-1 ring-inset ring-white/10 sm:inset-x-0 sm:rounded-t-xl" />
                <p className="relative mx-auto max-w-2xl text-base text-white sm:text-center">
                {feature.description}
                </p>
            </div>
            <div className="mt-10 w-[45rem] overflow-hidden rounded-xl bg-slate-50 shadow-xl shadow-blue-900/20 sm:w-auto lg:mt-0 lg:w-[67.8125rem]">
                <img
                className="w-full"
                src={feature.image}
                alt=""
                priority
                sizes="(min-width: 1024px) 67.8125rem, (min-width: 640px) 100vw, 45rem"
                />
            </TabPanels>
            </TabPanel>
        ))}
        </div>
    </>
    )}
</TabGroup>

I am converting the TailwindUI Salient template (preview) from Next.Js to SolidJS and they use the Tab.Panels component in the main feature section so that the correct screenshot (on the right side) is shown for the selected feature (on the left side).

Even if Tab.Panels does nothing and this is something on my end I still feel like you should still expose a version of it that just acts as a div to bridge the gap for people who are migrating existing HeadlessUI code over to solid-headless. Other than this everything else had a direct counterpart for the code I was converting over.

Thanks for the quick reply and love the library!

oscartbeaumont avatar Sep 23 '22 03:09 oscartbeaumont

Are you certain that Tab.Panels does nothing?

Technically speaking when it comes to the official specification of Tabs, there is no mention of tab panels or panel groups in general, so this is up to the user how would they handle the layout problem for the tab panels. Unless it's actually desirable there's no motivation for me to introduce it yet.

Take note that, and mentioned in the README, solid-headless isn't 1-to-1 with HeadlessUI.

lxsmnsyc avatar Sep 23 '22 09:09 lxsmnsyc

@oscartbeaumont I am using the TailwindUI Salient template and had the same issue as you.

After thinking it was due to not having the TabPanels component, I realized that I was using the callback variables incorrectly.

Before:

clsx(isSelected ? '...' : '...')

After:

clsx(isSelected(feature.title) ? '...' : '...')

And here is one of the full For loops if you wanted to how I used the above

<For each={props.features}>{(feature)=>(
  <div class={clsx('group relative rounded-full py-1 px-4 lg:rounded-r-none lg:rounded-l-xl lg:p-6',
    isSelected(feature.title) ? 'bg-white lg:bg-white/10 lg:ring-1 lg:ring-inset lg:ring-white/10' : 'hover:bg-white/10 lg:hover:bg-white/5'
)}>
    <h3>
      <Tab value={feature.title}  class={clsx('font-display text-lg [&:not(:focus-visible)]:focus:outline-none',
        isSelected(feature.title) ? 'text-green-600 lg:text-white' : 'text-green-100 hover:text-white lg:text-white')}>
        <span class="absolute inset-0 rounded-full lg:rounded-r-none lg:rounded-l-xl" />
           {feature.title}
      </Tab>
    </h3>
    <p class={clsx('mt-2 hidden text-sm lg:block',
       isSelected(feature.title) ? 'text-white' : 'text-green-100 group-hover:text-white' )}>
       {feature.description}
    </p>
  </div>
)}</For>

And then for the Panel, I do something like:

<For each={props.features}>{(feature)=>(
  <TabPanel value={feature.title} unmount={false}>
    <div class={clsx(isSelected(feature.title) ? 'visible' : 'hidden')}>
    ....

And this will hide the panels as needed while still showing all the tabs.

KjellConnelly avatar Dec 01 '22 23:12 KjellConnelly