Switching Theme Dynamically in a Multi-tenant Next.js + Tailwind App

I'm currently developing a Next.js + Tailwind application that supports multiple tenants and allows each tenant to easily switch styles or themes.

I've been struggling with the idea of how to implement this feature without requiring a rebuild of the entire application every time a style is changed. Is there a way to dynamically update the style for one specific tenant without having to rebuild the whole app?

My goal is to have tenants change a style parameter, which would then update a database. When the tenant's web app is refreshed, the new style should be applied instantly without any delay or need for a full rebuild.

Answer №1

Implement React's Context feature to dynamically display styles such as light or dark mode.

Alternatively,

Utilize a state management tool or the browser's localStorage to control styles and toggle classes for HTML elements within a Tailwind CSS setup.

Answer №2

My solution involved a combination of analyzing URLs and passing server props to the client side.

For instance, I made sure my backend sent certain styles like primaryColor.

Here is a functional example:

  1. Before rendering in your page.tsx file, extract the tenantId from the URL and use it to fetch styles from the backend.
async function retrieveQueryParams() {
  const headersInstance = headers();
  const pathname = headersInstance.get("referer");
  if (!pathname) return new URLSearchParams();

  const urlSearchParams = new URLSearchParams(pathname.split("?")[1]);
  return urlSearchParams;
}

async function fetchStyles(tenantId: string) {
  try {
    const response = await fetch(`http://localhost:3000/themes/${tenantId}`);
    return response.json();
  } catch (error) {
    return {};
  }
}
  1. Access this data in your server component and pass it to your client component
export default async function Main({searchParams){
  const tenantId = searchParams?.tenantId || "";
  const styles = await fetchStyles(tenantId);

  return (
    <div>
      <ClientComponent styles={styles} />
    </div>
  )
}
  1. In your client component, dynamically update the global CSS variables
const ClientComponent = ({styles}) => {
  useEffect(() => {
    document.documentElement.style.setProperty("--primary-color", primaryColor);
  }, [primaryColor]);

return (
<div className="bg-primary w-100 h-100">
my colour has been changed
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 10 Reactive Form - Controlling character limit in user input field

I'm currently developing an Angular 10 reactive form and I am looking for a way to restrict the maximum number of characters that a user can input into a specific field. Using the maxLength Validator doesn't prevent users from entering more chara ...

Next.js link is lacking a href tag

When I enclose my text in Link, the <a href is missing in the DOM (although the link still works). Is this good for SEO? How does an SEO robot know that there is a link? import Link from 'next/link' . . . <Link href="/about"> ...

How to trigger a click event in React using TypeScript and material-ui library

Currently, I am facing an issue when trying to update the value of material-ui TextFields from the store. When manually typing inside the field, everything works fine as expected with the handleChange() and handleBlur() functions handling the events. Howev ...

Is it possible to utilize Webpack 5's ChunkGroup API with several entries?

I am encountering an error message when attempting to upgrade from Webpack 4 to Webpack 5. The error states: Module.entryModule: Multiple entry modules are not supported by the deprecated API (Use the new ChunkGroup API) I have searched for information o ...

Tips for Enhancing Your Build Strategy in Next.js Applications

I have set up a Next.js application on digitalocean and I am using pm2 to manage it as a process. Everything is functioning properly, except for when I push changes to the server. Both create react app and Next.js become unavailable during the build proce ...

The external library is incorrectly interpreting the path as null instead of its actual value when using usePathname - Next13

Recently, I encountered an issue with an external library that relied on the useRouter function to fetch the pathname. However, after transitioning to Next.js 13 and switching to usePathname instead of useRouter, I discovered that the hook was returning nu ...

The Angular2 view is failing to display updated data from a shared service

I've been struggling to show data from my shared service, but it's not displaying. Can someone please help me out? I've been stuck on this for the past few days. I've tried NgZone and ChangeDetectorRef, but they haven't worked for ...

React TypeScript - creating a component with a defined interface and extra properties

I'm completely new to Typescript and I am having trouble with rendering a component and passing in an onClick function. How can I properly pass in an onClick function to the CarItem? It seems like it's treating onMenuClick as a property of ICar, ...

Exploring the Differences between Angular's Http Module and the Fetch API

While I grasp the process Angular uses for HTTP requests, I find myself leaning towards utilizing the Fetch API instead. It eliminates the need to subscribe and unsubscribe just for a single request, making it more straightforward. When I integrated it int ...

GitHub Action CI/CD for a Next.js app's directory path

I'm currently facing an issue while deploying from the app directory to Github Action CI/CD. I keep running into a PageNotFoundError: Cannot find module for page: / error, indicating that I may not be able to access the app path in my structure. Here& ...

How can we reduce the size of a JSON object in Typescript before sending it to the client?

Currently, I am faced with a common challenge. I have a database object that is a standard JS object originating from a document database, and my goal is to transmit this object to the client. However, certain fields contain sensitive information that shou ...

Trouble with Font registration in react-pdf within NextJS framework

When I created a React application, I successfully used the package and imported my own fonts like this: import PrometoRegular from '../../assets/fonts/Prometo-Regular.ttf'; // Register font Font.register({family: 'PrometoRegular', sr ...

Executing a function by click event using the onclick attribute from a file located in the public directory of my project (Next

I'm new to using Next.js and I have a question about how to utilize onclick to execute a function from an external file located in my public folder. Below is my index.js file: import Head from "next/head" import Script from "next/scrip ...

Contrasting ./ and $ in React project module imports

The creator of this particular project has utilized a different path to import a component: import { client } from '$lib/graphql-client' I'm curious: What is the significance of the $ symbol in this case? How does it differ from something ...

Is the next.config.js file overlooked by Vercel on a preview domain?

I'm currently in the process of establishing a development domain for my NextJS application on Vercel. Within my next.config.js, I have granted access to my API routes from any source. This setup functions perfectly in my live production environment. ...

My shadcn ui DataTable does not seem to be reloading when I invalidate the query. Can anyone help

I have encountered an issue while using Nextjs, tanstack/react-query, and shadcnui library. I am working with three components: Substance List, Shadcn DataTable, and Shadcn Columns. The problem arises when a record is deleted, as the Table component fails ...

Cannot send response headers once they have already been sent to the client [NEXTJS]

Currently, I am engrossed in a personal project focused on creating a dashboard using NextJS. This project serves as an opportunity for me to delve into learning NextJS and the fundamental concepts of TypeScript. My primary challenge at the moment revolves ...

The function getServerSideProps does not return any value

I'm a beginner with Next.js and I'm currently using getServerSideProps to retrieve an array of objects. This array is fetched from a backend API by utilizing the page parameters as explained in the dynamic routes documentation: https://nextjs.org ...

Determine the Nautical Miles Between Various Coordinate Points using React

Does anyone have a solution for calculating nautical miles using react? Let's say I have this object: const calculateDistance = [ {point_id: 1, long: longitude , lat: latitude}, {point_id: 2, long: longitude , lat: latitude}, {point_id: 3, ...

Implementing query parameters in a Deno controller

I developed a couple of APIs for a Deno Proof of Concept. This is the route implementation: const router = new Router() router.get('/posts', getPosts) .get('/posts/:id', getPostsById) In the second route, I successfully retriev ...