CaptainCSS on GitHub

Cluster

An object for clustering groups of dynamic width elements together, with a consistent space between them, even when stacking responsively

Default class reference

Class
Properties
cluster--cluster-x-space: 1rem;
--cluster-y-space: 1rem;
overflow: hidden;
cluster > *align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
margin: calc((var(--cluster-y-space) / 2) * -1)
        calc((var(--cluster-x-space) / 2) * -1);
cluster > * > *margin: calc(var(--cluster-y-space) / 2)
        calc(var(--cluster-x-space) / 2);
cluster--0--cluster-x-space: 0px;
--cluster-y-space: 0px;
cluster--1--cluster-x-space: 0.25rem;
--cluster-y-space: 0.25rem;
cluster--2--cluster-x-space: 0.5rem;
--cluster-y-space: 0.5rem;
cluster--3--cluster-x-space: 0.75rem;
--cluster-y-space: 0.75rem;
cluster--4--cluster-x-space: 1rem;
--cluster-y-space: 1rem;
cluster--5--cluster-x-space: 1.25rem;
--cluster-y-space: 1.25rem;
cluster--6--cluster-x-space: 1.5rem;
--cluster-y-space: 1.5rem;
cluster--7--cluster-x-space: 1.75rem;
--cluster-y-space: 1.75rem;
cluster--8--cluster-x-space: 2rem;
--cluster-y-space: 2rem;
cluster--9--cluster-x-space: 2.25rem;
--cluster-y-space: 2.25rem;
cluster--10--cluster-x-space: 2.5rem;
--cluster-y-space: 2.5rem;
cluster--11--cluster-x-space: 2.75rem;
--cluster-y-space: 2.75rem;
cluster--12--cluster-x-space: 3rem;
--cluster-y-space: 3rem;
cluster--14--cluster-x-space: 3.5rem;
--cluster-y-space: 3.5rem;
cluster--16--cluster-x-space: 4rem;
--cluster-y-space: 4rem;
cluster--20--cluster-x-space: 5rem;
--cluster-y-space: 5rem;
cluster--24--cluster-x-space: 6rem;
--cluster-y-space: 6rem;
cluster--28--cluster-x-space: 7rem;
--cluster-y-space: 7rem;
cluster--32--cluster-x-space: 8rem;
--cluster-y-space: 8rem;
cluster--36--cluster-x-space: 9rem;
--cluster-y-space: 9rem;
cluster--40--cluster-x-space: 10rem;
--cluster-y-space: 10rem;
cluster--44--cluster-x-space: 11rem;
--cluster-y-space: 11rem;
cluster--48--cluster-x-space: 12rem;
--cluster-y-space: 12rem;
cluster--52--cluster-x-space: 13rem;
--cluster-y-space: 13rem;
cluster--56--cluster-x-space: 14rem;
--cluster-y-space: 14rem;
cluster--60--cluster-x-space: 15rem;
--cluster-y-space: 15rem;
cluster--64--cluster-x-space: 16rem;
--cluster-y-space: 16rem;
cluster--72--cluster-x-space: 18rem;
--cluster-y-space: 18rem;
cluster--80--cluster-x-space: 20rem;
--cluster-y-space: 20rem;
cluster--96--cluster-x-space: 24rem;
--cluster-y-space: 24rem;
cluster--px--cluster-x-space: 1px;
--cluster-y-space: 1px;
cluster--0.5--cluster-x-space: 0.125rem;
--cluster-y-space: 0.125rem;
cluster--1.5--cluster-x-space: 0.375rem;
--cluster-y-space: 0.375rem;
cluster--2.5--cluster-x-space: 0.625rem;
--cluster-y-space: 0.625rem;
cluster--3.5--cluster-x-space: 0.875rem;
--cluster-y-space: 0.875rem;
cluster--x-0--cluster-x-space: 0px;
cluster--x-1--cluster-x-space: 0.25rem;
cluster--x-2--cluster-x-space: 0.5rem;
cluster--x-3--cluster-x-space: 0.75rem;
cluster--x-4--cluster-x-space: 1rem;
cluster--x-5--cluster-x-space: 1.25rem;
cluster--x-6--cluster-x-space: 1.5rem;
cluster--x-7--cluster-x-space: 1.75rem;
cluster--x-8--cluster-x-space: 2rem;
cluster--x-9--cluster-x-space: 2.25rem;
cluster--x-10--cluster-x-space: 2.5rem;
cluster--x-11--cluster-x-space: 2.75rem;
cluster--x-12--cluster-x-space: 3rem;
cluster--x-14--cluster-x-space: 3.5rem;
cluster--x-16--cluster-x-space: 4rem;
cluster--x-20--cluster-x-space: 5rem;
cluster--x-24--cluster-x-space: 6rem;
cluster--x-28--cluster-x-space: 7rem;
cluster--x-32--cluster-x-space: 8rem;
cluster--x-36--cluster-x-space: 9rem;
cluster--x-40--cluster-x-space: 10rem;
cluster--x-44--cluster-x-space: 11rem;
cluster--x-48--cluster-x-space: 12rem;
cluster--x-52--cluster-x-space: 13rem;
cluster--x-56--cluster-x-space: 14rem;
cluster--x-60--cluster-x-space: 15rem;
cluster--x-64--cluster-x-space: 16rem;
cluster--x-72--cluster-x-space: 18rem;
cluster--x-80--cluster-x-space: 20rem;
cluster--x-96--cluster-x-space: 24rem;
cluster--x-px--cluster-x-space: 1px;
cluster--x-0.5--cluster-x-space: 0.125rem;
cluster--x-1.5--cluster-x-space: 0.375rem;
cluster--x-2.5--cluster-x-space: 0.625rem;
cluster--x-3.5--cluster-x-space: 0.875rem;
cluster--y-0--cluster-y-space: 0px;
cluster--y-1--cluster-y-space: 0.25rem;
cluster--y-2--cluster-y-space: 0.5rem;
cluster--y-3--cluster-y-space: 0.75rem;
cluster--y-4--cluster-y-space: 1rem;
cluster--y-5--cluster-y-space: 1.25rem;
cluster--y-6--cluster-y-space: 1.5rem;
cluster--y-7--cluster-y-space: 1.75rem;
cluster--y-8--cluster-y-space: 2rem;
cluster--y-9--cluster-y-space: 2.25rem;
cluster--y-10--cluster-y-space: 2.5rem;
cluster--y-11--cluster-y-space: 2.75rem;
cluster--y-12--cluster-y-space: 3rem;
cluster--y-14--cluster-y-space: 3.5rem;
cluster--y-16--cluster-y-space: 4rem;
cluster--y-20--cluster-y-space: 5rem;
cluster--y-24--cluster-y-space: 6rem;
cluster--y-28--cluster-y-space: 7rem;
cluster--y-32--cluster-y-space: 8rem;
cluster--y-36--cluster-y-space: 9rem;
cluster--y-40--cluster-y-space: 10rem;
cluster--y-44--cluster-y-space: 11rem;
cluster--y-48--cluster-y-space: 12rem;
cluster--y-52--cluster-y-space: 13rem;
cluster--y-56--cluster-y-space: 14rem;
cluster--y-60--cluster-y-space: 15rem;
cluster--y-64--cluster-y-space: 16rem;
cluster--y-72--cluster-y-space: 18rem;
cluster--y-80--cluster-y-space: 20rem;
cluster--y-96--cluster-y-space: 24rem;
cluster--y-px--cluster-y-space: 1px;
cluster--y-0.5--cluster-y-space: 0.125rem;
cluster--y-1.5--cluster-y-space: 0.375rem;
cluster--y-2.5--cluster-y-space: 0.625rem;
cluster--y-3.5--cluster-y-space: 0.875rem;

Usage

The cluster object is used when you want to evenly space several fluid-width elements, such as buttons or tags, both horizontally and vertically.

It applies an even margin on all sides of each element within the cluster, which makes them correctly spaced, even when wrapping onto multiple lines.

It then applies a negative margin around the whole element, which, with the help of overflow: hidden, chops off any excess margin that we don't want and pulls all the children flush against the container edge.

This makes the cluster perfectly space the items, without adding any extra margin on the outsides. Great!

Items are evenly spaced on all sides, even when wrapping

An item
Another item
One more item
Another one
There are now 5 items in this cluster
Here is item six
Two more
Enough
<div class="cluster">
    <div>
      <div>An item</div>
      <div>Another item</div>
      <div>One more item</div>
      <div>Another one</div>
      <div>There are now 5 items in this cluster</div>
      <div>Here is item six</div>
      <div>Two more</div>
      <div>Enough</div>
    </div>
</div>

The Cluster object in Captain provides a standardised way to define a cluster of items, and then use it effortlessly.

The negative margin

Note that the cluster has an extra element inside it that wraps the clustered items. This is to apply a negative margin that chops off the extra margin on the items inside, and pulls the cluster items flush against the container.

The following example shows the margin between the items, and the thick purple line is the container. Any margin outside the container is completely hidden and will not affect any other elements.

1
2
3
4
5
6
<div class="cluster">
    <div> <!-- Extra div required unless using { support: { cssFlexGap } } -->
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
    </div>
</div>

Do include the extra element

  <div class="cluster">
    <div>
      <div>An item</div>
    </div>
  </div>

Don't forget the extra element, or your cluster items will be partially hidden

  <div class="cluster">
-   <div>
      <div>An item that's cut off</div>
-   </div>
  </div>

If you're using any kind of component-based framework or partials, you can easily move this extra div into a Cluster component, which allows you to completely forget about it.

When support for Flex Gap (`gap`) becomes wider, we can drop this extra element. Support for it in Captain is already available. To make use of it early, add `flexGap` to the `captain.support` object in `tailwind.config.js`. At time of writing it's unavailable in Safari, and only recently in Chrome.

Semantic markup

Clustered items are often lists, so it's useful to mark them up semantically. This helps screen readers know there is a list, and count how many items are in the list.

You could do the following:

  <div class="cluster">
    <ul>
      <li>First list item</li>
      <li>Second list item</li>
      ...
    </ul>
  </div>

See customization options for more information on customizing the spacing between the cluster items.

Modifiers

Spacing size

The cluster class also includes spacing modifiers out of the box. The default config creates these classes from Tailwind's space config, which in turn defaults to Tailwind's global spacing config.

A cluster without a modifier defaults to a spacing of 1rem.

An item
Another item
One more item
Another one
There are now 5 items in this cluster
Here is item six
Two more
Enough
An item
Another item
One more item
Another one
There are now 5 items in this cluster
Here is item six
Two more
Enough
<div class="cluster cluster--0.5">
    <div>
      <div>An item</div>
      <div>Another item</div>
      <div>One more item</div>
      <div>Another one</div>
      <div>There are now 5 items in this cluster</div>
      <div>Here is item six</div>
      <div>Two more</div>
      <div>Enough</div>
    </div>
</div>

<div class="cluster cluster--8">
    <div>
      <div>An item</div>
      <div>Another item</div>
      <div>One more item</div>
      <div>Another one</div>
      <div>There are now 5 items in this cluster</div>
      <div>Here is item six</div>
      <div>Two more</div>
      <div>Enough</div>
    </div>
</div>

You can also size x and y spacing independently, using classes like cluster--x-8 and cluster--y-10.

An item
Another item
One more item
Another one
There are now 5 items in this cluster
Here is item six
Two more
Enough
<div class="cluster cluster--x-6 cluster--y-2">
    <div>
      <div>An item</div>
      <div>Another item</div>
      <div>One more item</div>
      <div>Another one</div>
      <div>There are now 5 items in this cluster</div>
      <div>Here is item six</div>
      <div>Two more</div>
      <div>Enough</div>
    </div>
</div>

Responsive

You're also able to adjust the size of the cluster when the active breakpoint changes:

An item
Another item
One more item
Another one
There are now 5 items in this cluster
Here is item six
Two more
Enough
<div class="cluster cluster--1 md:cluster--2 lg:cluster--6 xl:cluster--8">
    <div>
      <div>An item</div>
      <div>Another item</div>
      <div>One more item</div>
      <div>Another one</div>
      <div>There are now 5 items in this cluster</div>
      <div>Here is item six</div>
      <div>Two more</div>
      <div>Enough</div>
    </div>
</div>

Customizing

Gap

To change the gaps available to the cluster class, specify the name and gap size using the gap option in the theme.cluster section of your config file:

// tailwind.config.js
module.exports = {
  theme: {
    cluster: (theme) => ({
+     gap: {
+       DEFAULT: '1rem',
+       ...theme('space'),
+     },
    }),
  },
}

If you only have a single cluster gap size, you can specify a single size as a shorthand:

// tailwind.config.js
module.exports = {
  theme: {
    cluster: {
+     gap: '1rem',
    },
  },
}

Variants

By default, only responsive variants are generated for cluster utilities.

You can control which variants are generated for the cluster utilities by modifying the cluster property in the variants section of your tailwind.config.js file.

For example, this config will disable all variants:

  // tailwind.config.js
  module.exports = {
    variants: {
      // ...
+     cluster: [],
    }
  }

Disabling entirely

If you don't plan to use the cluster utilities in your project, you can disable them entirely by setting the cluster property to false in the captain.plugins section of your config file:

  // tailwind.config.js
  module.exports = {
    captain: {
      plugins: {
        // ...
+       cluster: false,
      }
    }
  }