Josh Kautz
Josh Kautz

Reputation: 631

How can I replicate the GridToolbarFilterButton badge animation with GridToolbarColumnsButton using Material UI component library?

This question is specific to usage of the Material UI React component library. I've created a functioning Code Sandbox example, available this link. I am using the Data Grid component, and the default behavior of the Filter button (GridToolbarFilterButton) is such that it shows a Badge over the button's icon. This is not default behavior of the Columns button (GridToolbarColumnsButton), but I've managed to add and achieve the same functionality.

One thing that I am having trouble with is getting the same animation / transition to happen them the badge becomes visible or invisible. On the Filter button, you can see that the badge has an animation where it seems to grow into view, and then shrink out of view. On the Columns button, it just immediately appears or disappears. I've spent some time trying to look at the Material UI source code to see if I can piece it together, but it feels just a little bit out of my reach at the moment.

Any thoughts on how I might be able to mimic that same animation for the Columns button? Happy to provide additional information. I've included a GIF animation of the Code Sandbox I provided, hopefully this will be a helpful visualize of differing animations between the badge appearing/disappearing on both buttons. Based on this pull request on the MUI-X project, it seems that perhaps the MUI team might be doing something related to this in the relatively near future.

enter image description here

Upvotes: 2

Views: 67

Answers (1)

Raghavendra N
Raghavendra N

Reputation: 6044

The grow/shrink animation of the badge works when the class MuiBadge-invisible is removed or added to the Badge element.

Why this animation is not working for the Badge on the columns button?

It is not working because when the columnVisibilityModel changes, the whole toolbar section is getting re-rendered. So when the hidden columns count is more than 1, then the Badge element is re-rendered without the class MuiBadge-invisible. So the transition from invisible to visible is not happening.

Solution:

Solution is we need to mimic the class transition by following these steps:

  • Always render the Badge with old value
  • After a slight delay (~50ms) update the badge count. Then Badge component will add the class based on the count. So you will see the grow/shrink animation.

Check this working CodeSandbox link. I've updated this section of the code in the CodeSandbox.

function MyButton({ prevCount, currentCount }) {
  const [count, setCount] = useState(prevCount);

  useEffect(() => {
    setTimeout(() => {
      setCount(currentCount);
    }, 50);
  }, [currentCount]);

  return (
    <Badge color="primary" badgeContent={count}>
      <GridColumnIcon />
    </Badge>
  );
}

export default function App() {
  const [columnVisibilityModel, setColumnVisibilityModel] = useState(
    Object.fromEntries(columns.map((column) => [column.field, true]))
  );
  const [prevCount, setPrevCount] = useState(0);
  const [currentCount, setCurrentCount] = useState(0);

  useEffect(() => {
    setPrevCount(currentCount);
    setCurrentCount(
      Object.entries(columnVisibilityModel).filter(
        ([key, value]) => value === false
      ).length
    );
  }, [columnVisibilityModel]);

  return (
    <DataGridPro
      rows={rows}
      columns={columns}
      columnVisibilityModel={columnVisibilityModel}
      onColumnVisibilityModelChange={(newModel) =>
        setColumnVisibilityModel(newModel)
      }
      slots={{
        toolbar: () => {
          return (
            <GridToolbarContainer>
              <GridToolbarColumnsButton
                startIcon={
                  <MyButton prevCount={prevCount} currentCount={currentCount} />
                }
              />
              <GridToolbarFilterButton />
            </GridToolbarContainer>
          );
        },
      }}
    />
  );
}

And this is how it looks:

MUI Badge - Grow/Shrink animation

Upvotes: 1

Related Questions