[00:00] Let's turn up the heat on this table and instead of rendering three rows, let's render 10, 000 rows. So I'm going to cut this data variable out. I'm going to open my editor and create a file called data.tsx. Here I'm going to paste and instead of data, I'm going to highlight, hit command K, prompt cursor to write a function that will create 10, 000 rows of data in this format. That seems good enough.
[00:59] I don't want it to call the data, though. It's looping 10, 000 times, and it creates the same sort of object and returns that data. So I'm fine with this. I'll export generate data. Inside of app, we have a problem because data is undefined.
[01:21] We'll go here, we'll import data and generate data. So when we go back over to our browser, you can see this white screen. I'm on a relatively high-powered machine, but Chrome, or Brave rather, is taking a little bit to render 10, 000 rows. I just hit reload and it took a little bit. Once it's loaded, it seems to scroll pretty fine.
[02:00] But if we inspect and look, you'll see there's lots and lots of rows being rendered at the DOM. One way to optimize tables where there's thousands of rows, or if not thousands, maybe sometimes millions, you can virtualize a list. So we're going to be implementing 10-stack virtual. 10-stack Virtual essentially keeps a virtual index of all the items in this list, and it returns the visible items, so you can tell it to render however many items are on the screen and then give it an overscan and it will render 30 and then five items below the fold. And even though there's 10, 000 items in the list, the browser only knows about 35 of them at a time.
[03:12] So let's go over to our terminal. And we will yarn add tan stack react virtual. Back in our code, we can now import. There are two exports out of React Virtual that you could use. There's one where it's use window virtualizer.
[03:46] Where it's use window virtualizer, and then there's another, and then there's another import use virtualizer. The main difference is window virtualizer uses the browser window as the container and useVirtualizer, you have to render the items into a container yourself, like a div or whatever. We're going to be using useWindowVirtualizer, just because it's easier, no real reason. So we will instantiate our row virtualizer. We have to pass in the count.
[04:48] Cursor's a little bit wrong here. Oops. We don't get scroll element. We estimate the size. I happen to know that the size is 37, not 45.
[05:04] Our overscan is how many items do we render below the fold. So right now, we just wanna render five items. You can adjust this. It will depend on your specific use case on how many items you want to render below the fold. So now that we have our virtual rows and our table rows, we can go ahead and render them.
[06:04] Instead of rendering table rows dot get row model dot rows, cursor is Most likely correct here. So now we're mapping on the virtual rows, and this will be however many rows are being viewed plus the overscan. Inside of this map function, we pull out the actual row that we want to render. Here we render the table row and then the table cell. When we go over to our browser, you can see that it's not rendering 10, 000 rows.
[06:58] And there's some CSS we need to write to get this to work. The browser doesn't know that this table actually needs to be a much bigger size, so it's only rendering the initial size. So there's a couple things that we'll have to write to actually get the virtualizer working. First on the table body we will call class name equals relative and width full. Next we will add a style and we'll add a height of get total size.
[07:51] Now that we have the height of the table body, we'll check and see what it did. It rendered, you can see the scroll bar got very small, but we have some funky behavior going on. And that is because we are not finished. So for each table row, we will need to tell the row where in the list the row is. So we'll add instead of row.id we'll do virtual row.key.
[08:31] We don't want this stuff that cursor added. We'll go class name equals absolute and flex and then width full. Next we'll go style and we'll add transform and then translate Y And each virtual row has a start position, and we want to tell the browser to render each row in its subsequent start position. So this will get a little bit, translate Y will translate this row a little bit lower for each row. So we go over here.
[09:36] Now you can see we can render through a list. You'll notice that the widths got all messed up and we'll fix that next. But when you inspect, you can see that the browser is only rendering a small number of rows now. When we reload, it reloads instantly because the browser doesn't have to do a huge paint. Now let's fix the column widths on each of our cells.
[10:16] So in our table cell we will add a style and the width will be cell.column.getSize So back in our browser you'll see these widths changed but they're still not lining up to the headers. So what we need to do is go to the headers and for the table header row, we will add class name, cursor's wrong again, flex and width, full. And then on each table head element, we will add class name with full and style with get header size. So back in our browser, now you can see our column headers match. When we add a column, We have a little bit of CSS that we could write to not let this cell overflow with that cell, but we're going to just hide the website for now.
[12:01] Now when we scroll, this all works. One thing that you want to be aware of is when you're virtualizing a table, for accessibility reasons The screen reader won't know how many rows are in this table because we've now virtualized the list. So we have to tell the screen reader with the aria row count attribute, how many, so instead of get row count, that could work, but We can also go data.length. This will tell the screen reader that there are this many rows in the table. That's some information that is useful to know when low-sighted or blind people are accessing your page.
[13:09] Now that we have a virtual list, TanStack Virtual gives us some utilities that we can use to scroll the list. So we can add a button, and this button can be scroll to bottom. And now whenever we click, the row virtualizer will scroll to this specific index and then at the bottom we can go button scroll to top. Scroll to top. So here now we have our scroll to bottom button and our scroll to top.
[14:00] One thing to note with the virtualizer, we have to use style attributes like this. One reason is because The values are in the virtualizer themselves, so we have to somehow get the values out of JavaScript and pass them to CSS. And the Style object is a convenient way to do that. You can't, in Tailwind, you can't interpolate a string like this and pass it to an attribute. Sometimes you can go height, some arbitrary number of pixels like this, but interpolating this variable into the Tailwind class, this will not work because Tailwind needs static classes to build correctly.
[15:06] So that's one reason why we're using the style object when generally you don't necessarily want to use the style object, especially when you have a CSS framework like Tailwind. But React Virtual is an exception that I have made in projects.