Home > Enterprise >  Tailwind CSS Dynamic State Updates But Not Rendered Correctly
Tailwind CSS Dynamic State Updates But Not Rendered Correctly

Time:01-29

My design has 3 divs. A left panel (filters), the main content which contains a cards displayed in a grid and a right panel (info). The side panels have a button which user can open and close like a drawer. I offset the main content by using tailwinds ml for margin-left relative to the left panels width and similar to right.

If panel is opened, extend width and update the grid's left offset with margin left. And vice versa.

Here is my code. The right panel works fine. But the left panel is problematic. By default the left panel is open. When I click on the button to close it via the callback method with toggleFilterVisibility the panel closes but the grid displays with no margin (which completely covers the left panel to re-open). I inspected the component's states and they are updating with the callback as expected. I also removed the ml-[${filterPanelWidth}px] with the string literals ml-[65px] and ml-[250px] which are rendered correctly.

I suspect I am implementing the dynamic render with tailwind incorrect or its rendering before waiting for the state updates somehow. console.log(filterPanelWidth) and clicking the button shows the correct state changes for both filterPanelWidth and filterPanelVisibility.

<div className={`bg-gray-100 pt-14 ml-[${filterPanelWidth}px]`}>
import FilterPanel from "../components/FilterSidePanel";
import InfoPanel from "../components/InfoSidePanel";
import CardGridPanel from "../components/CardGridPanel";

const HomeRoute: React.FC = () => {
  const [filterPanelWidth, setFilterPanelWidth] = useState(250);
  const [isFilterPanelVisible, setFilterPanelVisibility] = useState(true);
  const [infoPanelWidth, setInfoPanelWidth] = useState(45);
  const [isInfoPanelVisible, setInfoPanelVisiblity] = useState(false);

  const toggleFilterVisibility = () => {
    if (isFilterPanelVisible) {
      setFilterPanelWidth(65);
    } else {
      setFilterPanelWidth(250);
    }
    setFilterPanelVisibility(!isFilterPanelVisible);
  };

  const toggleInfoVisibility = () => {
    if (isInfoPanelVisible) {
      setInfoPanelWidth(45);
    } else {
      setInfoPanelWidth(600);
    }
    setInfoPanelVisiblity(!isInfoPanelVisible);
  };

  return (

    <>
      <div className="main-content w-full bg-gray-100">
        <div className="flex">
          <div className="left-sidepanel-content bg-white fixed h-screen">
            <FilterPanel toggleVisibility={toggleFilterVisibility} isVisible={isFilterPanelVisible}/>
          </div>
          <div className={`bg-gray-100 pt-14 ml-[${filterPanelWidth}px]`}>
            <CardGridPanel />
          </div>
          <div className={`right-sidepanel-content right-0  bg-white w-[${infoPanelWidth}px] fixed h-screen`}> 
            <InfoPanel toggleVisibility={toggleInfoVisibility} isVisible={isInfoPanelVisible}/>
          </div>
        </div>
      </div>
    </>
  );
};

export default HomeRoute;

Update 1: After looking at the docs I see I tried to apply the dynamic rendering for tailwind like so:

          <div className="bg-gray-100 pt-14 {{ isFilterPanelVisible ? 'ml-[250px]' : 'ml-[65px]' }}">
            <CardGridPanel />
          </div>

but when inspecting the elements I see the following literal string. How do I resolve this? I also tried to replace the quotes with backticks enter image description here

CodePudding user response:

You can't make dynamic class names like that in Tailwind. The classes must be compile-time constants. Instead of doing ml-[${filterPanelWidth}px] you must do something like isFilterPanelVisible ? 'ml-[65px]' : 'ml-[250px]'. You can read more about it in the Tailwind docs.

  • Related