Implementing Theming in Sitecore Headless XM Cloud With Tailwind CSS

Streamlining Dynamic Theming with Sitecore and Tailwind CSS

July 1, 2024

By Sohrab Saboori

Implementing Theming in Sitecore Headless XM Cloud With Tailwind CSS

When building modern web applications, theming is an essential feature that enhances user experience by allowing dynamic changes in the appearance of the application. In this blog, we'll explore how to implement theming in Sitecore Headless XM Cloud using Tailwind CSS for each component, ensuring a flexible and scalable approach to styling.

Step 1: Setting Up Themes in Sitecore

First, you need to create a theme configuration under Presentation/Style in your Sitecore Headless XM Cloud setup. Name this configuration Theme and define variables such as blue and white. Assign values to these variables like bg:white and bg:blue. These themes should then be assigned to all components across your application.

A screenshot in Sitecore XM Cloud showing the new "Theme" value under styles

An image showing the two new variables under the "Theme" item, white and blue

Step 2: Accessing Styles in Your Code

Within your component's code, the theme can be accessed from the params.style object, which you define in Sitecore. For example, in your React component, you can access this style via props.params?.Styles.

Step 3: Parsing Rendering Properties

Create a utility function to parse these styles effectively. This function will be placed in a file named rendering-props.ts under the util folder. Here’s how you define it:

import { mapping } from './rendering-props-mapping';

export type RenderingPropsMapping = { [key: string]: { [subKey: string]: string }; };

type RenderingProps = { bg: string;

};

const parseRenderingProps = (input: string | undefined): RenderingProps => { const result: RenderingProps = { bg: mapping.bg.default,

};

if (!input) { return result; }

const properties = input.split(' ');

properties.forEach((prop) => { const [propertyKey, value] = prop.split(':');

<span class="hljs-keyword">if</span> (!propertyKey || !value) {
  <span class="hljs-keyword">return</span>;
}

<span class="hljs-keyword">switch</span> (propertyKey) {
  <span class="hljs-keyword">case</span> <span class="hljs-string">'bg'</span>:
    result.bg = mapping.bg[value] ?? mapping.bg.default;
    <span class="hljs-keyword">break</span>;

  <span class="hljs-keyword">default</span>:
    <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`Invalid rendering property key: <span class="hljs-subst">${propertyKey}</span>`</span>);
    <span class="hljs-keyword">break</span>;
}

});

return result; };

export { parseRenderingProps }; export type { RenderingProps };

This function takes a string input, splits it into properties, and assigns values based on the predefined mapping. It helps dynamically assign classes based on the component’s theme configuration.

Step 4: Defining Rendering Props Mapping

Create a mapping file (rendering-props-mapping.ts) to map the styling values to the appropriate CSS classes:

import { RenderingPropsMapping } from './rendering-props';

// Your mapping object export const mapping: RenderingPropsMapping = { bg: { blue: 'theme-blue', black: 'theme-black', green: 'theme-green', white: 'theme-white', grey: 'theme-grey', default: 'theme-white', },

};

Step 5: Styling Components With Global CSS and Tailwind

Define your themes in the global.css file and use Tailwind plugins to create utility classes that apply these theme styles:

.theme-white {
  --bg: var(--next-white);
  --accent: var(--next-white);
  --accent-2: var(--next-blue);
  --text: var(--next-black);
}

Tailwind CSS offers extensive customization capabilities, allowing you to define your themes based on the unique requirements of your project. In your Tailwind configuration, the plugins section is particularly useful for adding custom properties and utilities that match your theming system. This allows you to create a more dynamic and adaptable styling environment.

Here's how you can define customizable properties in the plugins section of your Tailwind configuration:

plugins: [
   // Custom plugin for adding theme-specific utilities
  plugin(({ addUtilities }) => {
    addUtilities(themeClasses({ name: 'background', colorVariable: 'bg' }));
    addUtilities(themeClasses({ name: 'copy', colorVariable: 'text' }));
    addUtilities(themeClasses({ name: 'accent', colorVariable: 'accent' }));
    addUtilities(themeClasses({ name: 'accent-2', colorVariable: 'accent-2' }));
  }),
];

Step 6: Utilizing and Applying Rendering Props in Components

Once you have set up your theming structure and parsing functions, the next crucial step is to integrate these into your components. This involves initializing and applying the parsed rendering properties to manage your component's styling dynamically based on the theme.

First, initialize the rendering properties using the parseRenderingProps function within your component's state:

const [renderingProps, setRenderingProps] = useState<RenderingProps>(() => {
  return parseRenderingProps(props.params?.Styles);
});

This step extracts the theme-related styles from props.params?.Styles and stores them in your component’s state. This state will automatically update your component's classes whenever the theme changes.

Next, apply these styles directly within your component's structure to ensure that the theme is applied dynamically:

<div className={`${renderingProps.bg} mx-auto max-w-7xl background-bg copy-text xl:pl-2`} data-component="text-banner">
  {/* Component content here */}
</div>

Here, you are using the className attribute to apply the background and text styles dynamically. The class names background-bg and copy-text are examples of utilities that you might define in your Tailwind configuration, allowing for seamless theme changes.

Visual Examples: Blue and White Themes in Action

Blue Theme Example:

An image showing the "Blue" variable running on a webpage with developer tools open. Underlining the variables that are injected through the blue theme and displaying an example banner with a blue background and white text.

White Theme Example:

An image showing the "White" variable running on a webpage with developer tools open. Underlining the variables that are injected through the white theme and displaying an example banner with a white background and black text.

These examples serve as a practical demonstration of how themes can dramatically alter the look and feel of your components with minimal changes in the backend code.

Final Word on Theming in Sitecore Headless XM Cloud With Tailwind CSS

We've detailed how to implement dynamic theming in Sitecore Headless XM Cloud using Tailwind CSS, enhancing both aesthetics and consistency across components. By following the outlined steps and leveraging Tailwind's customization, you can significantly improve your application's user experience. Our examples, including the blue and white themes, illustrate the practical impact of these theming techniques.

Effective theming involves thoughtful integration of CSS variables and utility classes, combining Sitecore's capabilities with Tailwind's styling tools. With this approach, you can create a responsive, visually appealing interface that adapts to various design needs.



Photo of Fishtank employee Sohrab Saboori

Sohrab Saboori

Senior Full-Stack Developer

Sohrab is a Senior Front-End Developer with extensive experience in React, Next.js, JavaScript, and TypeScript. Sohrab is committed to delivering outstanding digital solutions that not only meet but exceed clients' expectations. His expertise in building scalable and efficient web applications, responsive websites, and e-commerce platforms is unparalleled. Sohrab has a keen eye for detail and a passion for creating seamless user experiences. He is a problem-solver at heart and enjoys working with clients to find innovative solutions to their digital needs. When he's not coding, you can find him lifting weights at the gym, pounding the pavement on the run, exploring the great outdoors, or trying new restaurants and cuisines. Sohrab believes in a healthy and balanced lifestyle and finds that these activities help fuel his creativity and problem-solving skills.