Taylor Finklea
Taylor Finklea

Reputation: 1

Dynanically change tailwindcss color based on user input in Vue3/Nuxt3

I am trying to build a way for a user to define the primary color of the website. When defining my tailwind classes, I want to use something like bg-primary-600 rather than hard coding a color, so that when the value for primary changes, it will update the style.

Here I have my test environment: https://stackblitz.com/edit/nuxt-starter-qinx8e?file=tailwind.config.js

For those who don't want to open the link

tailwind.config.js

/** @type {import('tailwindcss').Config} */
const colors = require('tailwindcss/colors');

module.exports = {
  darkMode: 'class',
  content: [
    './components/**/*.{js,vue,ts}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './nuxt.config.{js,ts}',
    './app.vue',
  ],
  theme: {
    extend: {
      colors: {
        // This should be changed by the user instead of hard coding
        primary: colors.blue,
      },
    },
  },
};

app.vue

<template>
  <div>
    <div class="bg-red-600 h-16 mb-4">HELLO WORLD</div>
    <div class="bg-primary-600 h-16 mb-4">HELLO WORLD</div>
    <button class="bg-blue-200 rounded-lg p-4 mx-2" @click="myColor = 'blue'">
      Blue
    </button>
    <button class="bg-green-200 rounded-lg p-4" @click="myColor = 'green'">
      Green
    </button>
    <body class="mx-2">
      My color is: {{ myColor }}
    </body>
  </div>
</template>

<script setup>
const myColor = ref('orange');
</script>

I cannot seem to figure out how to dynamically change the color in Tailwind. I'm able to hard code a value like in my example, but I cannot assign this value to a reactive variable and have it update.

I cannot figure out how to make the myColor ref update the color in tailwind. Note that I don't want to update it just in the page, I need to be able to update tailwind so that any reference to primary, regardless of the page or component will have the correct color.

Upvotes: 0

Views: 2785

Answers (3)

onomio
onomio

Reputation: 381

In addition to Daniel's answer, you can use tailwind's color variations. But you'll need to create those yourself.

This is how that would look in your tailwind config.

theme: {
  extend: {
    colors: {
      primary: {
        50: "var(--color-navbar-50)",
        100: "var(--color-navbar-100)",
        200: "var(--color-navbar-200)",
        300: "var(--color-navbar-300)",
        400: "var(--color-navbar-400)",
        500: "var(--color-navbar-500)",
        600: "var(--color-navbar-600)",
        700: "var(--color-navbar-700)",
        800: "var(--color-navbar-800)",
        900: "var(--color-navbar-900)",
        950: "var(--color-navbar-950)",
      },
    },
  },
}

And then you add each of those to the document's style property.

document.documentElement.style.setProperty("--color-primary-50", "#fef1fa");
document.documentElement.style.setProperty("--color-primary-100", "#fee5f7");
document.documentElement.style.setProperty("--color-primary-200", "#feccf1");
document.documentElement.style.setProperty("--color-primary-300", "#ffa2e5");
document.documentElement.style.setProperty("--color-primary-400", "#fd69d0");
document.documentElement.style.setProperty("--color-primary-500", "#f83cb9");
document.documentElement.style.setProperty("--color-primary-600", "#ea2ea2");
document.documentElement.style.setProperty("--color-primary-700", "#ca0c7c");
document.documentElement.style.setProperty("--color-primary-800", "#a70d66");
document.documentElement.style.setProperty("--color-primary-900", "#8b1056");
document.documentElement.style.setProperty("--color-primary-950", "#550231");

According to tailwind's documentation, the color palettes are manually created and there's no algorithm to generate custom palettes. There are multiple websites though that provide generators and apis such as this one https://www.tints.dev, that allow you to create a palette from a base color.

Daniel's answer is a good basis how to implement the CSS variables, but I would suggest to move the management itself out of the component and into a separate module.

Upvotes: 0

Taylor Finklea
Taylor Finklea

Reputation: 1

I figured out how to dynamically set the primary color and still maintain the ability to do things like bg-primary-600. Now I just need to figure out how to make the user able to change this value, but that's a cookie issue not a tailwindcss issue.

I split up the export into separate blocks, so that I could dynamically define my theme block based on the value of a variable.

tailwind.config.js

/** @type {import('tailwindcss').Config} */
const colors = require('tailwindcss/colors');
const color = 'blue';

exports.darkMode = 'class';

exports.content = [
  './components/**/*.{js,vue,ts}',
  './layouts/**/*.vue',
  './pages/**/*.vue',
  './plugins/**/*.{js,ts}',
  './nuxt.config.{js,ts}',
  './app.vue',
];

if (color === 'blue') {
  exports.theme = {
    extend: {
      colors: {
        primary: colors.blue,
      },
    },
  };
}
if (color === 'green') {
  exports.theme = {
    extend: {
      colors: {
        primary: colors.green,
      },
    },
  };
}
if (color === 'orange') {
  exports.theme = {
    extend: {
      colors: {
        primary: colors.orange,
      },
    },
  };
}

Upvotes: -1

Daniel
Daniel

Reputation: 35684

You can use CSS variables to achieve that

In your tailwind config, set primary as a CSS var:

  theme: {
    extend: {
      colors: {
        // This should be changed by the user instead of hard coding
        primary: 'var(--color-primary)',
        // This will extend functionality of your color
        // so you can use opacity on it like text-secondary/80
        // var has to have rgb in it not hex color like: --color-info: 14 165 233;
        secondary: 'rgb(var(--color-secondary) / <alpha-value>)'
      },
    },
  },

Then you can override the var in the app using style.setProperty:

<template>
  <div>
    <div class="bg-primary h-16 mb-4">HELLO WORLD</div>
    <button class="bg-blue-200 rounded-lg p-4 mx-2" @click="myColor = 'blue'">
      Blue
    </button>
    <button class="bg-green-200 rounded-lg p-4" @click="myColor = 'green'">
      Blue
    </button>
    <body class="mx-2">
      My color is: {{ myColor }}
    </body>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';
const colors = {
  blue: '#0077FF',
  green: '#00DD77',
};
const myColor = ref('orange');
watch(myColor, (color) => {
  document.documentElement.style.setProperty('--color-primary', colors[color]);
});
</script>

<style>
:root {
  --color-primary: #ff9900;
}
</style>

Note that tailwind will not be able to determine the color variations, so you cannot use bg-primary-500 or bg-primary-200 you need to drop the number i.e. bg-primary and text-primary etc.

Upvotes: 4

Related Questions