Working with grids with slots is difficult due to missing Astro CSS

Created on 27 February 2025, 10 days ago

Overview

I have a component that uses slots. The challenge is that inside the slot, Astro adds an <astro-slot> element, which breaks the grid handling. To mitigate this, Astro recommends adding following CSS:

astro-island, astro-slot, astro-static-slot {
  display:contents;
}

However, this conflicts with XBs annotation handling which has the following code:

[data-xb-slot-id], [data-xb-region], [data-xb-region] > .region {
    position: relative;
    display: flow-root;
}

This is the component I have built:

import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils";

const gridVariants = cva(
  "mx-auto grid w-full max-w-[1360px] place-items-center gap-4",
  {
    variants: {
      cardLayout: {
        "2 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-2",
        "3 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3",
        "4 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4",
        "6 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-6",
      },
    },
    defaultVariants: {
      cardLayout: "3 column",
    },
  },
);

const CardContainer = ({
  heading,
  cardLayout,
  cards,
}) => {
  return (
    <div className="my-18 flex flex-col items-center gap-16 md:my-24">
      {heading}
      <div className={cn(gridVariants({ cardLayout }))}>{cards}</div>
    </div>
  );
};


export default CardContainer;

Proposed resolution

User interface changes

🐛 Bug report
Status

Active

Version

0.0

Component

Theme builder

Created by

🇫🇮Finland lauriii Finland

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @lauriii
  • 🇫🇮Finland lauriii Finland
  • 🇬🇧United Kingdom jessebaker

    Adding:

    astro-island, astro-slot, astro-static-slot {
      display:contents;
    }
    

    breaks both the Overlay and SortableJS meaning you basically can't use XB!

    The overlay (for both slots and components) relies on being able to get the boundingClientRect of the components and slots it is mirroring but that doesn't work with display:contents as those elements then have no box size. This can possibly be worked around by detecting that CSS and instead basing the overlay size on the combined size of the children of the element.

    SortableJS must have some internal check for the sortable items' size too because as soon as you add display: contents to the sortable items they stop working.

  • 🇺🇸United States effulgentsia

    I think the fix for this is to add a JS file to the astro.hydration library that adds an event handler for the astro:only event that Astro fires after hydration completes, and in this event handler, remove the <astro-slot> and <astro-island> wrapper elements (i.e., remove them as wrappers by moving their children up to their parent). This would then match what SSR will do once we add SSR support. This would only be for components that don't depend on client state. Reactive components would still need these wrappers. But so long as this works for non-reactive components, people can solve grid issues by, for example, nesting non-reactive grid container components inside a reactive component that needs a grid.

    In the meantime, the specific component in the issue summary can be made to work with this trick:

    const gridVariants = cva(
    -  "mx-auto grid w-full max-w-[1360px] place-items-center gap-4",
    +  "mx-auto grid w-full max-w-[1360px] place-items-center gap-4 [&>astro-slot]:grid [&>astro-slot]:grid-cols-subgrid",
      {
        variants: {
          cardLayout: {
    -        "2 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-2",
    +        "2 columns": "grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-2 [&>astro-slot]:col-span-2",
    

    Hat tip to @lauriii, @larowlan, and @balintbrews for figuring out the above subgrid approach.

Production build 0.71.5 2024