{
  "$type": "site.standard.document",
  "canonicalUrl": "https://johnnyreilly.com/posts/mui-react-tree-view-pass-data-to-treeitem",
  "description": "Learn how to pass arbitrary data to individual nodes in the MUI treeview component so individual nodes can be customised; for instance implementing a loader.",
  "path": "/posts/mui-react-tree-view-pass-data-to-treeitem",
  "publishedAt": "2024-07-01T00:00:00.000Z",
  "site": "at://did:plc:yy3apqjlms24kso7ahn7lbmb/site.standard.publication/3mova7c4nho2b",
  "tags": [
    "react",
    "mui"
  ],
  "textContent": "I'm a big fan of the Material-UI (MUI) library treeview component. I recently needed to do some customisation of the nodes in the treeview component I was rendering. The application I was working on acquired data for each node in our treeview component asynchronously. I wanted to show a loader for each node that was still loading.\n\nAchieving this required passing data to individual nodes in the treeview component. This appears to not be officially supported by the MUI treeview component. However, it is possible and this post will show you how to do it.\n\nThe comment on this GitHub issue suggests that this will be directly supported in MUI v6. Until that time, you'll have to slightly hack the component to achieve this.\n\nI've written previously about how to check children and uncheck parents in the MUI treeview component. This post builds on that one. But, you need not be using multiselect / checkboxes etc to use the approach in this post. It applies generally to usage of the treeview component.\n\n\n\nThe behaviour we want to implement\n\nIn the application I'm working on, we load data for each node in our treeview that is selected. While a nodes data is loading, we want to show a loader so users know that work is being done. We want to achieve something like this:\n\nThe labels in the above GIF aren't relevant to this post. The key thing to note is that the treeview is showing a loader for nodes that are still loading. Strictly speaking, the loader is a spinner from the MUI library. The CircularProgress component to be precise. However, the loader could be anything you like.\n\nThe question is: how do we pass data to individual nodes in the treeview component so we can customise them?\n\nThe code\n\nWe can achieve this by using the slots and slotProps props on the RichTreeView component. (If you're using the SimpleTreeView that should work the same.) The slots prop allows us to customise the rendering of the treeview components. The slotProps prop allows us to pass data to the customised components. \"Slots\" is a MUI approach to customising components. You can read more about it here.\n\nThe code below demonstrates how to pass data to individual nodes in the treeview component:\n\nThe two key parts of the code above are the slots and slotProps props. In slots, we're passing a TreeItemWithLoading component to customise the rendering - we'll implement that component in moment. We're also passing a data-still-to-load-ids prop to the TreeItemWithLoading component. This is the data we want to pass to the individual nodes in the treeview component. In our case, it's a list of node ids that we're still loading the data for. You could pass any data you like here.\n\nThe thing that's probably (hopefully) setting off alarm bells in your head is the //@ts-expect-error comment. This is in place because MUI doesn't officially support passing data to individual nodes in the treeview component, and consequently TypeScript shouts about it. However, passing arbitrary data does work. It will be received by the rendering component and so can be used. The comment is there to acknowledge that this is a hack and to get TypeScript to stop complaining about it.\n\nNow let's look at the TreeItemWithLoading component:\n\nThe TreeItemWithLoading component is a wrapper around the TreeItem2 component. You'll note in our code we're using the TreeItem2 component. I won't explicitly discuss this, but it's worth noting that the TreeItem2 component is intended to replace the TreeItem component in a future version of MUI; the TreeItem2 component is more flexible and allows for more customisation.\n\nAnyway, the TreeItemWithLoading component is where the magic happens. For every node in the treeview, this component will be rendered. All it does is render a TreeItem2 component, but with some customisation. Again using the slots / slotProps properties, it customises the underlying label component that is rendered. It replaces the default label component (TreeItem2Label) with a custom one that shows a loader if the node is still loading, that component is named TreeItemLabelWithLoading. We'll implement it in a moment.\n\nThe TreeItemWithLoading component is also responsible for passing the data-is-loading prop to the TreeItemLabelWithLoading component. You'll note that we're just passing a boolean this time which we construct by comparing the id of the node to the list of ids that are still loading.\n\nFinally, let's look at the TreeItemLabelWithLoading component:\n\nThis is just a wrapper of the TreeItem2Label component that would have been rendered by default. The only difference being: if the data-is-loading value passed is truthy, a loader (CircularProgress) component is rendered next to the label to indicate the loading state.\n\nConsider the image below:\n\nNotice that there are three nodes in this picture. Two without a loader, one with. This is the result of the logic in our TreeItemLabelWithLoading component.\n\nPutting it all together\n\nNow we've walked through how it works, let's put all the code together in one place:\n\nThe above will allow you to pass data to the components rendering the elements that make up your treeview, and allow you to customise accordingly.\n\nI'm not completely certain this is \"the way\" that is advised. But it is a way that works. I'm going to follow up with the MUI team to ensure this is good advice.",
  "title": "MUI React Tree View: pass data to TreeItem"
}