Logo
Published on

Building a Flexible Grid Component in Sitecore Headless with Tailwind

Authors
  • avatar
    Name
    Jorge Lusar
    Twitter

When working with Sitecore Headless JSS, one of the common needs is to give content authors more control over page layouts. Sitecore ships with a ColumnSplitter.tsx component out of the box, but it relies on Twitter Bootstrap’s grid system.

In projects where Tailwind CSS is already the chosen styling framework, Bootstrap can feel redundant. That’s why I decided to create a Tailwind-powered Grid component that reuses the logic of the ColumnSplitter while replacing Bootstrap’s markup with Tailwind’s grid utilities.

The result? A leaner, more consistent way to manage layouts—without adding another CSS framework into the mix.

Example grid with 5 columns using Tailwind spans

The Problem with the Default Column Splitter

The default ColumnSplitter.tsx works fine, but it comes with some drawbacks if your team has standardized on Tailwind:

  • Bootstrap dependency: Pulls in an entire framework just for layout utilities.
  • Rigid markup: It uses Bootstrap’s row/col structure, which doesn’t map neatly to Tailwind.
  • Styling inconsistency: Mixing Bootstrap and Tailwind often leads to bloated, conflicting stylesheets.

The Tailwind Approach

Here’s the custom Grid component I built. It lets authors configure grid layouts through Sitecore component parameters, but under the hood it leverages Tailwind’s grid utilities under /Presentation/Styles/Grid:

  • Grid columnslg:grid-cols-2, lg:grid-cols-3, lg:grid-cols-4, lg:grid-cols-6
  • Grid column spanlg:col-span-1, lg:col-span-2, lg:col-span-3, lg:col-span-4

This gives editors freedom to define how many columns appear and how wide each column should be.

src/components/Grid.tsx
import {
  ComponentParams,
  ComponentRendering,
  Placeholder,
} from '@sitecore-jss/sitecore-jss-nextjs';
import { clsx } from 'clsx';

interface GridProps {
  params: ComponentParams;
  rendering: ComponentRendering & { params: ComponentParams };
}

const Grid = ({ params, rendering }: GridProps): JSX.Element => {
  const enabledPlaceholders = params.EnabledPlaceholders.split(',');
  const id = params.RenderingIdentifier || undefined;
  const styles = params.Styles;
  const columnStyles = [
    params.Styles1,
    params.Styles2,
    params.Styles3,
    params.Styles4,
    params.Styles5,
    params.Styles6,
    params.Styles7,
    params.Styles8,
  ];

  return (
    <section className={clsx(styles ?? styles)} id={id}>
      <div
        className={clsx(
          'container grid max-w-[1062px] gap-6',
          styles ?? styles
        )}
      >
        {enabledPlaceholders.map((ph, index) => {
          const phKey = `column-${ph}-{*}`;
          const phStyles = `${columnStyles[+ph - 1] ?? ''}`.trimEnd();

          return (
            <div key={index} className={phStyles}>
              <Placeholder key={index} name={phKey} rendering={rendering} />
            </div>
          );
        })}
      </div>
    </section>
  );
};

export default Grid;

Benefits of This Approach

1. Tailwind Consistency

Everything stays in the Tailwind ecosystem—no more mixing and matching with Bootstrap. That means a smaller CSS footprint, consistent design tokens, and cleaner utility-based classes.

2. Lightweight and Performant

Dropping Bootstrap removes unnecessary bloat. Tailwind is already optimized for production builds, so the CSS bundle remains lean.

3. Editor Flexibility

By mapping Sitecore component parameters directly to Tailwind grid classes, authors can:

  • Pick how many columns the grid should have
  • Control column spans per placeholder
  • Apply extra Tailwind utility classes when needed

This strikes a balance between editor freedom and developer guardrails.

4. Reusable and Scalable

The logic mirrors Sitecore’s default ColumnSplitter, but is framework-agnostic. This makes it easier to extend—whether that’s adding responsive breakpoints, custom gaps, or even CSS grid templates for advanced layouts.

5. Cleaner Separation of Concerns

The component handles structure, while Tailwind handles styling. No custom CSS overrides, no Bootstrap grid quirks—just a semantic grid with utility classes applied.


Real Usage Example

To show how this works in practice, let’s look at a grid configured with:

  • Grid layout: lg:grid-cols-3
  • Column spans:
    • Column 1 → lg:col-span-3
    • Column 2 → lg:col-span-1
    • Column 3 → lg:col-span-2
    • Column 4 → lg:col-span-2
    • Column 5 → lg:col-span-1

In the Sitecore Page Builder, it looks like this:

Example 1 Example 2 Example 3 Example 4 Example 5 Example 6 Example 7

Each dashed box represents a placeholder where editors can drop components. The Tailwind classes (lg:col-span-*) determine how much space each column takes up in the grid.

This approach lets editors visually compose complex layouts—all while keeping the underlying CSS simple and Tailwind-driven.


Final Thoughts

Replacing Bootstrap’s ColumnSplitter with a Tailwind-driven Grid may seem like a small change, but it has an outsized impact:

  • Cleaner CSS bundles
  • More predictable layouts
  • Happier developers (and editors)

If you’re building a Sitecore Headless + Tailwind project, this approach keeps your stack focused and future-proof.