skip to Main Content

I am sending a tailwind color green-500 from the prop bgColor and then use it inside the after:border-b-${bgColor} in the positionStyles object.

But tailwind is unable to dynamically parse after:border-b-${bgColor} as a tailwind class.

How to solve this issue? I am open to new suggestions or ways to rewrite my code.

What I want is to pass just a color like green-500 and then let tailwind render it as a class.

Following is my code:

const TOOLTIP_POSITIONS = {
  TOP: "TOP",
  RIGHT: "RIGHT",
  BOTTOM: "BOTTOM",
  LEFT: "LEFT",
};

const ToolTip = ({
  title,
  position = TOOLTIP_POSITIONS.BOTTOM,
  isOverflowX = false,
  noTooltip = false,
  zindex,
  bgColor = "green-500",
  keys = [],
  children,
}) => {

  const positionStyles = {
    [TOOLTIP_POSITIONS.BOTTOM]: `top-[100%] mt-2
    after:content-[""] 
    after:absolute
    after:top-[-5px]
    after:left-2/4
    after:-translate-x-2/4
    after:w-0
    after:h-0
    after:border-l-[6px] after:border-l-transparent
    after:border-b-[6px] after:border-b-${bgColor}
    after:border-r-[6px] after:border-r-transparent`,
  };

  return (
    <div
      className={`tooltip-wrapper group relative flex w-full items-center justify-center font-medium`}
    >
      {children}
      <div
        className={`tooltip absolute hidden w-max rounded-lg bg-gray950 p-2 text-center text-white group-hover:flex group-hover:items-center ${positionStyles[position]}`}
      >
        {title}
      </div>
    </div>
  );
};

2

Answers


  1. As per the documentation:

    The most important implication of how Tailwind extracts class names is that it will only find classes that exist as complete unbroken strings in your source files.

    If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS:

    Don’t construct class names dynamically

    <div class="text-{{ error ? 'red' : 'green' }}-600"></div>
    

    In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes.
    Instead, make sure any class names you’re using exist in full:

    Always use complete class names

    <div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
    

    You could:

    • Have the entire class in the bgColor prop like

      const ToolTip = ({
        …
        bgColor = "after:border-b-green-500",
        …
      }) => {
        const positionStyles = {
          [TOOLTIP_POSITIONS.BOTTOM]: `
          …
          after:border-b-[6px] ${bgColor}
          …`,
        };
      
    • Have a dictionary for color to Tailwind class names:

      const ToolTip = ({
        …
        bgColor = "green-500",
        …
      }) => {
        const DICTIONARY = {
          'green-500': 'after:border-b-green-500',
          // …
        };
        const positionStyles = {
          [TOOLTIP_POSITIONS.BOTTOM]: `
          …
          after:border-b-[6px] ${DICTIONARY[bgColor]}
          …`,
        };
      
    • Use the style attribute for truly dynamic colors, if theme can be converted to a valid CSS color value (or you could get the color from Tailwind):

      import resolveConfig from 'tailwindcss/resolveConfig';
      import tailwindConfig from './tailwind.config.js';
      
      const fullConfig = resolveConfig(tailwindConfig);
      
      // …
      
      const ToolTip = ({
        …
        bgColor = "green-500",
        …
      }) => {
        const positionStyles = {
          [TOOLTIP_POSITIONS.BOTTOM]: `
          …
          after:border-b-[6px] after:border-b-[color:--color]
          …`,
        };
      
        return (
          <div …>
            {children}
            <div
              className={`… ${positionStyles[position]}`}
              style={{
                '--color': fullConfig.theme.borderColor[bgColor] || fullConfig.theme.borderColor[bgColor.split('-')[0]][bgColor.split('-')[1]],
              }}
            >
      
    • safelist the classes, if you have a limited number of known colors:

      module.exports = {
        safelist: [
          {
            pattern: /^border-b-(red|green|blue)-500$/,
            variants: ['after'],
          },
          // …
        ],
        // …
      ];
      
    Login or Signup to reply.
  2. Instead of using after:border-b-${bgColor} the whole class name should be variable meaning

    let bgColor = "border-b-red-200" // whole className should be static
    
    const positionStyles = {
       // ..other classes
       after:${bgColor}
       `,
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search