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

Created on 27 February 2025, 2 months 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

Merge Requests

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.

  • 🇬🇧United Kingdom jessebaker

    RE #3 - The sortableJS limitation/issue is not a problem any more as the work in 📌 Investigate drag-and-drop solution that removes the need to drop items into the preview iFrame Active has replaced SortableJS with DnDKit and no longer relies on the markup of elements in the iFrame for drag and drop.

    Adding display: contents to the astro-islands does still break the overlay even in that new solution - however it would just be one problem to solve now (detect astro-islands and base the size of the overlay on the immediate child instead).

    The alternative, proposed by @effulgentsia in #4 is also seemingly a viable route.

    I'd be interested in hearing @balintbrews' thoughts on this and which solution he favours?

  • 🇬🇧United Kingdom jessebaker
  • Merge request !930Add client.css to astro build → (Open) created by jessebaker
  • Pipeline finished with Success
    6 days ago
    #479246
  • Pipeline finished with Success
    6 days ago
    Total: 1723s
    #479323
  • Pipeline finished with Failed
    6 days ago
    Total: 1849s
    #479405
  • 🇬🇧United Kingdom jessebaker
  • Pipeline finished with Success
    4 days ago
    Total: 571s
    #481421
  • 🇬🇧United Kingdom jessebaker
  • 🇺🇸United States effulgentsia

    I recommend renaming client.css to hydration.css, since it's part of the hydration library, not the client library. Note that the hydration library is independent of UI framework, whereas the client library is specific to Preact.

    Also, as part of this issue, can we add header: true to the astro.hydration library, similar to how we do for the xb-ui library? That will ensure that the <astro-*> custom elements begin in an upgraded state, reducing layout shift on the actual site, and possibly also helping with 🐛 Overlay and iFrame flicker on updating props values Active while editing within XB.

  • Pipeline finished with Success
    3 days ago
    Total: 933s
    #481880
  • Pipeline finished with Canceled
    about 12 hours ago
    #483703
  • Pipeline finished with Failed
    about 12 hours ago
    #483705
Production build 0.71.5 2024