SAMIRA hs
SAMIRA hs

Reputation: 131

Using dynamic position values in Tailwind CSS

I want pass coordinate values to a component as props Using Tailwind CSS classes. The values change every mouse hover, but the classes are not working.

My component

    import classNames from "classnames";
    interface TooltipProps {
      coordinate: { left: string; top: string; isFavorite: boolean };
    }
    
    const Tooltip: React.FC<TooltipProps> = ({ coordinate }: TooltipProps) => {
      return (
        <div
          id="tooltip"
          className={classNames(
            `fixed ml-[auto] z-[999] p-[10px] text-sm font-medium text-white bg-gray-900 rounded-[6px] shadow-tooltip  dark:bg-gray-700`,
            coordinate.left,
            coordinate.top
          )}
        >
          {coordinate.isFavorite ? "حذف" : "افزودن"} به علاقه‌مندی
          <svg
            className="absolute  bottom-[-10px] center "
            width="16"
            height="10"
            viewBox="0 0 16 10"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path d="M8 10L0 0L16 1.41326e-06L8 10Z" fill="black" />
          </svg>
        </div>
      );
    };
    
    export default Tooltip;

and in the props I'm passing:

  setCoordinate({
    top: `top-[${Math.round(top)}px]`,
    left: `left-[${Math.round(left)}px]`,
  });

These values are not working using the Tailwind CSS utility classes.

Upvotes: 9

Views: 14138

Answers (6)

Chungnh98f
Chungnh98f

Reputation: 11

Tailwind has support for using data-attributes as modifiers; The ability to use values in your data attributes to toggle a tailwind class on or off.

Example:

<!-- Will apply -->
<div data-size="large" class="data-[size=large]:p-8">
  <!-- ... -->
</div>

<!-- Will not apply -->
<div data-size="medium" class="data-[size=large]:p-8">
  <!-- ... -->
</div>

Docs: https://tailwindcss.com/docs/hover-focus-and-other-states#data-attributes

Upvotes: 1

Nipun Ravisara
Nipun Ravisara

Reputation: 4471

Adding calculated style value to style attribute is the solution.

 <div 
    className={`bg-white h-4 w-0.5 ...`}
    style={{ left: `${normalizedPercentage}rem` }}
 />

Upvotes: 0

Ed Lucas
Ed Lucas

Reputation: 7355

Tailwind does not support dynamic classes, such as the ones you are trying to create. The full utility class name must be available at build time in your code for Tailwind to find it and generate the proper CSS classes.

For something as dynamic as coordinates, I would recommend using a style attribute along with the className attribute holding your Tailwind utility classes.

<div 
  id="tooltip"
  className="fixed ml-auto z-[999] p-[10px] text-sm font-medium text-white bg-gray-900 rounded-[6px] shadow-tooltip dark:bg-gray-700"
  style={{top: `${coordinate.top}px`, left: `${coordinate.left}px`}}
>

Then you can just pass the numeric position values to your component:

setCoordinate({
  top: Math.round(top),
  left: Math.round(left)
});

Additional information regarding Tailwind and dynamic classes: https://tailwindcss.com/docs/content-configuration#dynamic-class-names

Upvotes: 13

Ahmed Tounsi
Ahmed Tounsi

Reputation: 1550

As Toni mentioned, can’t depend on any sort of arbitrary dynamic values that change on the client-side. I suggest using inline styling to change the top and left values.

Apply these code changes.

    interface TooltipProps {
      coordinate: { left: number; top: number; isFavorite: boolean };
    }
    
    const Tooltip: React.FC<TooltipProps> = ({ coordinate }: TooltipProps) => {
      return (
        <div
          id="tooltip"
          className="fixed ml-[auto] z-[999] p-[10px] text-sm font-medium text-white bg-gray-900 rounded-[6px] shadow-tooltip  dark:bg-gray-700"
style={{top: `${coordinate.top}px`, left: `${coordinate.left}px`}}
          }
        >
          {coordinate.isFavorite ? "حذف" : "افزودن"} به علاقه‌مندی
          <svg
            className="absolute  bottom-[-10px] center "
            width="16"
            height="10"
            viewBox="0 0 16 10"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path d="M8 10L0 0L16 1.41326e-06L8 10Z" fill="black" />
          </svg>
        </div>
      );
    };
    
    export default Tooltip;
setCoordinate({
  top: Math.round(top),
  left: Math.round(left)
});

Upvotes: 1

MagnusEffect
MagnusEffect

Reputation: 3925

You can ${} to add any variable/dynamic value in the `` string. You can modify className like this

className={`fixed ml-[auto] z-[999] p-[10px] text-sm font-medium text-white bg-gray-900 rounded-[6px] shadow-tooltip  dark:bg-gray-700 ${coordinate.left} ${coordinate.right}`}

For more you can refer to this use-case and my answer:here

Upvotes: -4

Toni Bardina Comas
Toni Bardina Comas

Reputation: 1808

From the docs:

Tailwind doesn’t include any sort of client-side runtime, so class names need to be statically extractable at build-time, and can’t depend on any sort of arbitrary dynamic values that change on the client. Use inline styles for these situations, or combine Tailwind with a CSS-in-JS library like Emotion if it makes sense for your project.

https://v2.tailwindcss.com/docs/just-in-time-mode

Wrong

<div className={`mt-[${size === 'lg' ? '22px' : '17px' }]`}></div>

Correct

<div className={ size === 'lg' ? 'mt-[22px]' : 'mt-[17px]' }></div>

Upvotes: 4

Related Questions