0

im new at the React and Tailwindcss and i can't find any solution to my problem. I need to dynamiclly change background color my component but i can't.

I've tried almost anything but nothing worked. I need to map over categories.json file for the background property. I already customize the colors in tailwind.config.cjs.

WeeklyCard.jsx

import ellipsis from '../assets/images/icon-ellipsis.svg';

export default function WeeklyCard({
  title,
  titleBackground,
  titleImage,
  previousTime,
  currentTime,
}) {
  return (
    <div
      className={`relative overflow-hidden flex justify-end ${titleBackground} mb-5 h-[150px] w-[290px]   rounded-[10px]`}
    >
      <img
        className='w-[65px] h-[65px] absolute -top-2 right-3 '
        src={titleImage}
      />

      <div className='relative top-8  flex flex-col items-center justify-center h-[120px] w-[290px] rounded-[10px] p-6 bg-dark-blue  '>
        <div className='flex items-center justify-between w-full text-pale-blue'>
          <div className='text-lg'>{title}</div>
          <img className='w-[20px] h-[5px] cursor-pointer' src={ellipsis} />
        </div>
        <div className='flex items-center justify-between w-full text-pale-blue'>
          <div className='text-[28px] font-[300]'>{currentTime}hrs</div>
          <div className='text-[14px] text-desaturated-blue'>
            Last week - {previousTime}hrs
          </div>
        </div>
      </div>
    </div>
  );
}
App.jsx

import ProfileCard from './components/ProfileCard';
import WeeklyCard from './components/WeeklyCard';
import categories from './categories.json';

export default function App() {
  const weeklyCards = categories.map((categories) => (
    <WeeklyCard
      key={categories.title}
      title={categories.title}
      titleBackground={categories.titleBackground}
      titleImage={categories.titleImage}
      previousTime={categories.timeframes.weekly.previous}
      currentTime={categories.timeframes.weekly.current}
    />
  ));


  return (
    <div className={`h-min w-screen flex flex-col items-center justify-center bg-very-dark-blue`}>
      <ProfileCard
        profilePicture={'./src/assets/images/image-jeremy.png'}
        name='Jeremy Robson'
      />
      {weeklyCards}
    </div>
  );
}


categories.json

[
  {
    "title": "Work",
    "titleImage": "../src/assets/images/icon-work.svg",
    "titleBackground": "bg-Work",
    "timeframes": {
      "daily": {
        "current": 5,
        "previous": 7
      },
      "weekly": {
        "current": 32,
        "previous": 36
      },
      "monthly": {
        "current": 103,
        "previous": 128
      }
    }
  },
  {
    "title": "Play",
    "titleImage": "../src/assets/images/icon-play.svg",
    "titleBackground": "bg-Play",
    "timeframes": {
      "daily": {
        "current": 1,
        "previous": 2
      },
      "weekly": {
        "current": 10,
        "previous": 8
      },
      "monthly": {
        "current": 23,
        "previous": 29
      }
    }
  },
  {
    "title": "Study",
    "titleImage": "../src/assets/images/icon-study.svg",
    "titleBackground": "bg-Study",
    "timeframes": {
      "daily": {
        "current": 0,
        "previous": 1
      },
      "weekly": {
        "current": 4,
        "previous": 7
      },
      "monthly": {
        "current": 13,
        "previous": 19
      }
    }
  },
  {
    "title": "Exercise",
    "titleImage": "../src/assets/images/icon-exercise.svg",
    "titleBackground": "bg-Exercise",
    "timeframes": {
      "daily": {
        "current": 1,
        "previous": 1
      },
      "weekly": {
        "current": 4,
        "previous": 5
      },
      "monthly": {
        "current": 11,
        "previous": 18
      }
    }
  },
  {
    "title": "Social",
    "titleImage": "../src/assets/images/icon-social.svg",
    "titleBackground": "bg-Social",
    "timeframes": {
      "daily": {
        "current": 1,
        "previous": 3
      },
      "weekly": {
        "current": 5,
        "previous": 10
      },
      "monthly": {
        "current": 21,
        "previous": 23
      }
    }
  },
  {
    "title": "Self Care",
    "titleImage": "../src/assets/images/icon-self-care.svg",
    "titleBackground": "bg-SelfCare",
    "timeframes": {
      "daily": {
        "current": 0,
        "previous": 1
      },
      "weekly": {
        "current": 2,
        "previous": 2
      },
      "monthly": {
        "current": 7,
        "previous": 11
      }
    }
  }
]
tailwind.config.cjs

    /** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        'blue-primary': 'hsl(246, 80%, 60%)',
        Work: 'hsl(15, 100%, 70%)',
        Play: 'hsl(195, 74%, 62%)',
        Study: 'hsl(348, 100%, 68%)',
        Exercise: 'hsl(145, 58%, 55%)',
        Social: 'hsl(264, 64%, 52%)',
        SelfCare: ' hsl(43, 84%, 65%)',
        'very-dark-blue': ' hsl(226, 43%, 10%)',
        'dark-blue': ' hsl(235, 46%, 20%)',
        'desaturated-blue': ' hsl(235, 45%, 61%)',
        'pale-blue': ' hsl(236, 100%, 87%)',
      },
    },
  },
  plugins: [],
};
abgregs
  • 1,170
  • 1
  • 9
  • 17

1 Answers1

0

Here are a couple ways I've done it.

1. String Interpolation

You can use a template literal for string interpolation to pass an expression directly to className like so:

<div className={`base-class ${someBoolean ? "class-if-true" : "class-if-false"}`} />

2. A Utility Function

a) simple example

I find it handy to use something like this:

export function classNames(...classes) {
  return classes.filter(Boolean).join(' ');
}

b) a library like clsx

You could also use a library like clsx (https://github.com/lukeed/clsx) which offers a similar utility function but supports a variety of input types.

Example of Toggling Background Dynamically

Link to example: https://codesandbox.io/s/toggle-class-dynamically-example-b8gx3b

App.js

import "./styles.css";
import { useState } from "react";
function classNames(...classes) {
  return classes.filter(Boolean).join(" ");
}

export default function App() {
  const [blueBg, setBlueBg] = useState(false);
  const [hasBorder, setHasBorder] = useState(false);
  return (
    <div
      className={classNames(
        blueBg ? "blue-bg" : "red-bg",
        hasBorder && "with-border",
        "app"
      )}
    >
      Hit the Button to Toggle Background
      <button onClick={() => setBlueBg((prev) => !prev)}>
        Toggle Background Color
      </button>
      <button onClick={() => setHasBorder((prev) => !prev)}>
        Toggle Border
      </button>
    </div>
  );
}

styles.css

.app {
  font-family: sans-serif;
  text-align: center;
  width: 80%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  gap: 8px;
  font-size: 30px;
  color: white;
}

.with-border {
  border: black 20px solid;
}

button {
  font-size: 20px;
}

.blue-bg {
  background-color: blue;
}

.red-bg {
  background-color: red;
}

Explanation

This simple utility function lets you compose your list of classes. You can pass it a string for any default class names. You can also pass it expressions to conditionally include other class names. Falsy values will be discarded.

The example is contrived but the principle is the same. In your case you'll just be using Tailwind classes rather than the arbitrary custom classes I used.

I find this more readable when a long list of expressions is involved, but whatever you find works best for you.

abgregs
  • 1,170
  • 1
  • 9
  • 17