Digging into Virtual Scrolling
SmashingConf Freiburg 2022 / 47:08
Transcript
51 paragraphs
This is an automatic transcript of the recording above. It is published in full and unedited, apart from correcting names the recogniser reliably mishears. It will contain mistakes. More than one person speaks in this recording, so every paragraph is marked with whoever is talking, exactly as the captions name them.
00:08TEJAS:Thank you. Thanks a lot. It's so good to be here Smashing Conf Freiburg 2022. It's like the pandemic, looking at you, seeing all of you, I missed this, I missed the human connection, but I tell you what, seeing this and being part of this makes the last two years so insignificant because I'm with you now and I'm thankful for this. Give it a round of applause for recovery. Recovery. Now, before I get into this talk, that song was so good. Can we hear it for Toby? It's stuck in my head. So now, I can't move forward without singing this. Can we do a little bit of a sing along? Is that cool? If I remember, that's good! Really good and what's good is coming back again! Sing. That's good, really good, and what's good is coming back again! That's good, really good and what's good is coming back again!
01:20TEJAS:That's good, really good, and what's good is coming back again!. Thank you. [ Applause ] Amazing, man. Appreciate y'all. See, I got that over with, now I can move on with the talk. And there's a giant clock here telling me I wasted a bunch of time. I don't think it's a waste. We vibed, right? It's about the vibes, the positive energy, it's about the wonder, the curiosity, it's about the learning. But I see some of you are like move on. I'm getting there. Hi, my name is Tejas, that's pronounced like advantageous for those of you who struggle with Tejas, it means roof tiles in Spanish. I'm a roof tile, I guess, but two of them. I used to before the apocalypse, I would say I'm Tejas like contagious, but what can you do, you know? Advantageous has more syllables. But anyhow, I'm the director of developer relations at Xata. Xata's spelled like data but with an X for extended data.
02:31TEJAS:And I like that's funny. Cool, I'll laugh with you. And what we do is we have one job and that is to make the developer experience around databases phenomenal. For web developers, specifically. We want to have the data. You know, if you're writing SQL and you have to have indexes and all of -- and joins, it gets complex. We're like, why? We want it to be simple and comfortable and really nice to work. If you've used Vercel for deploying stuff, it's like that, but for databases. That's kind of what we try to do. That's our one thing. Why I'm talking to you about this is because this talk very much comes out of a use case, out of a case study, work that we had to do to get to this pleasant experience we're trying to go for.
03:19TEJAS:And my hope is that in sharing a case study from our real world experience, you'll come away with, you know, having learned a thing or two. And maybe some good vibes along the way. Does that sound OK? Awesome. So, what we have is a problem. We have a database, and when you try to look at your data in the database, right, you could have any number of records in there. You could have 10, you could have a million. And then, you meet the you meet the decision point, how do we deal with large sets of data in the browser? Do we paginate, split it up? If you have a million, you next page, next page. And there's problems, how big should a single page be? Should it be configureable? Should we choose a million per page and crash their browser and they're mad and this is good developer experience. Are you serious right now? No.
04:13TEJAS:So we had this decision, pagination, infinite scroll, which one? Infinite scroll, of course, is where you scroll to the bottom and you keep scrolling and scrolling. That's awesome. But the problem is, when you get to the bottom a lot and scroll a lot and append the page a lot, browsers have finite memory compared to your infinite ability to scroll. If you're on Twitter, you know what I'm talking about. So at some point, you accumulate so many elements in your browser, it starts to get slow or crash. How do we deal with millions of elements or perceivably millions of elements in the browser but really just having 10? And that is what we're called virtual scrolling. You show a subset of a large set, but feels like a large set. It's an illusion for good developer/user experience. And that's what we're here to talk about today. I need to share with you leaders start with why or something like this. I'm not interested in being a thought leader, but I like cool ideas and I thought I'd talk about this with my motivation.
05:23TEJAS:Why am I talking about this to you? And really, two reasons I feel this is important to talk about this very specific thing at Smashing Conf Freiburg, reason number one is a social motivation. This is cultural motivation. How many of you work in a software team? Yeah, that's a lot. Keep your hand up, if you work in the frontend team. That's more hands came in. I guess software is not frontend anyway. If you work in this, you've done what I did. You probably have constraints, you have timelines, you have deadlines, you have whatever, and you need to install like a UI library and use it. What you do, you go NPM install library, use it, awesome, done. How many of you do this? NPM install something and use it?
06:11TEJAS:Really all of these frontend developers and no one NPM installed. Stop lying to me. Anyway, I've done this, and NPM installed, met my deadline, moved on. I see here, though, room for improvement in myself. Because what I do is NPM install something, use it but won't really understand how it works. There's a lot of people who use React and it's awesome, but a few people who understand how it works inside. A lot of people install virtual scrolling libraries but few of us understand how we can go about implementing this. And it's not a bad thing. But I feel like we're missing out on the knowledge we can get by wondering how. So that's a social motivation. Number two is the technical motivation. As I said, this is a case study, something we had to do to meet technical limitations, like the browser's finite scrolling capabilities.
07:03TEJAS:In fact, instead of talking more about this, I'd rather show it to you with a demo. But before that, I need to be very clear here. This, the intention behind this talk and I need you to look at me because this is important. The intention behind this talk is information that hopefully leads to transformation in your career. It is education. I'm showing you the product we build for the case study, but this is not sales. If you leave here and you never use Xata, I do not care. What I do care about is you take things with you you can learn and put into practice at your jobs. Anyway, let's go over here to the laptop and if I can get my hands around this podium. This is what Xata looks like. I apologize for the flash of white mode. We have a great feature, it's that one. And so, this is what it looks like, it's alien to many of you and it doesn't matter, but for the purpose of the talk to illustrate the case study, these are work spaces, they're like organizations in GitHub, like a team.
08:05TEJAS:And if I choose the learning work space, we have some databases here. And I want to show you our need for virtual scrolling at a database, I'm going to create a shop. And in this database, my shop sells scooters. Why scooters? Because I really like them as a kid growing up. Not these e-scooters but the analog ones like a skateboard with handlebars. Let's add parameters. A scooter has a speed. And maybe a -- maybe a sort order. So sort order. I'll just add a scooter for posterity, speed 10, sort order 1, and now, I found a query in my app, I'm going to copy a JavaScript snippet and paste it in my console. And I get it and that's cool, but it's like one record, right? This is my scooter here.
08:56TEJAS:The problem is if you have a lot of these, we don't want to have a billion table rows. Just for learning, inject a million records. If you're using things in production, don't slam APIs like I'm about to. What we have here is a playground. I'm creating an array from a million records. The second argument is a mapping function. So I'm mapping them into sort, order and speed. And I'm going to insert them in batches of a thousand. Look at this code, while something create records. This can go very badly. So I'm creating a bunch of records here. And if I look at my table, I should see some -- there's a lot of stuff that's pretty -- I think I can maybe stop inserting before I destroy the servers. How many do we have? Let's sort this in descending order. We have 15,000.
09:59TEJAS:That should be enough for demo. And as I scroll, you'll notice there's not really 15,000 DOM elements here. There's actually one, two, three, four, five, six, seven, eight -- there's about 10. But it looks like there's 15,000. There's a few problems we ran into implementing this. I could scroll all day, literally. There's a few problems with this approach. I want to be up front about. The first one, you see the size of the scroll bar here, it's pretty large. It doesn't tell you it's 15,000 because it's so wide, looks like there's a lot. And the second thing, as I scroll to the end, what happens to the scroll bar? It jumps and halves in size. That's not really good UX accessibility. And also, a couple of things, if I try to jump -- pretend you don't see this. If I try and -- if I just try and jump to the bottom, watch what happens. I go to the bottom, it jumps back up. This is, I feel like it's a little bit deceptive because I don't really know where the bottom is. Can we do better? That's just to show you some of the technical motivation for talking about this and sharing things we've learned.
11:15TEJAS:Can we do better? The answer is probably/maybe. What I'd like to do in the time together is build that with you collaboratively. We write some code and see how it goes. OK. Again, the purpose is just learning, even if it goes wrong, whatever, we sang a song, that's enough for me. What I'm going to do, my terminal, make a directory called Smashing Conf, NPM, new project, and so, I did say this would be vanilla JavaScript, it won't. I mean, the things that we're doing with virtual scrolling, does translate. This is a 35-minute talk. And it's just more efficient to use JSS and React. It'll be clear for you in vanilla. Is that big enough? Is there enough contrast? That's -- OK, the side screens are probably better for you. NPM install, some dependencies, and let's test this conference WI-FI..
12:21TEJAS:And we'll open the editor here. And now, we have an editor with literally nothing. So we'll make a new -- if the font size is bad, shout. Be like, hey, I can't see. Pages index.tsx. We're just exporting a component here, nothing too scary. We'll return. Come on, co-pilot. Oh, awesome, thank you. So we will return H1, instead of Hello, World, let's make it personal, Smashing Conf. And we'll have that be the export default. And then it'll do whatever it does. And let's say, oops, I do not want to close. Let's save that and we'll NPM next dev. That will spin up the local server and we have Hello, Smashing Conf, nice, thank you whoever did that. Nice, but there's no data. What's the deal? Let's get some data into this. You could use the fetch API if you want. There's many ways you can do this. For the sake of Next.js, I'm doing this. OK, this makes live coding way faster.
13:33TEJAS:What we want, right, we want data from somewhere. And we want to return data as properties from this function that will then be inserted as data here, that's the goal. Where do we get this data from? We could use fetch, but for the sake of time, I'm going to use our tool. If I run here Xata in it, it'll give me whatever I want. It was the learning one. It was the shop, I believe, I do want. So this will generate typescript code for me, so I don't need to write anything myself. And really, the goal here is virtual scrolling. So all of the scaffolding stuff, let's get it out of the way. I have that. I can fetch data with it. Get Xata client, I think. There's also some configuration here, my goal is to move fast through the configuration because this is about virtual scrolling, right. These are node modules, explicitly, and now, I can get my data. I can do const data is 08, my client .db, .scooters, .getmany. We're talking about virtual scrolling, so I want size to be like 200.
14:49TEJAS:And now, I have data in my thing here, so let's use a table to visualize this. TR, TD -- I want the speed and I want the sort order. OK. Let's iterate through data, map it. Into these things. I hope this is followable, so far, if it's not, yell at me. The unique key is the item's ID. This is actually items -- I could do items speed. Does it work, though? Let's save, reload, ah, let's NPX next dev. And then, we should have -- OK, cool, we have data, whatever that is, I don't know. But here, this looks all right. The problem is, I don't like the way it looks. And I'll tell you what, I feel a bit, I'm here with all of you like designers and type face experts and I can't live with myself if it looks like this. I'm going to look at Pico CSS, it's like a drop-in style sheet to give a little esthetic, I'm going to plug that into my head tag.
16:09TEJAS:So now, I have a bunch of these things. Looks good. And we have 200 elements. What I want to implement is virtual scrolling. So I want to actually at any given time have like 15 elements in the DOM and as I scroll, it on the fly replaces them with the next 50, magic. That's kind of what I want to create. If we open the inspector, what we'll see in the element tree. Let's inspect this thing. We have TRs. Can you see that? The TR tags here? We have 200 of them. The goal is to have 15, but have it feel like 200. How do we go about that? We need to implement. First of all, there's multiple ways. I'm doing a 35-minute talk one, but you could use canvas, whatever you want. The technique is windowing where you create a window, that's a finite size container, you scroll in that thing and then on the scroll event, you swap stuff. To start with, we need a window. Let's create one. So how we can do that is first, let's define a maximum size for our window. We'll say it's I don't know 600 maybe.
17:20TEJAS:And we'll wrap this table in a div. You can see how this maps to HTML plain. That's why I chose. The height is the window height and we'll hide the overflow from my CSS people. Overflow auto. And cool, we have a window. We can scroll in it. And the cool thing, the scroll bar is the right size and everything. We haven't solved problems yet. Now, what we need to do is mathematics. We need to find out. Now, let me sort this by sort order. This 1 in 1,000 and 2 and stuff like this, doesn't really give me a nice vibe. So let me just quickly sort this. Sort by sort order, and we'll say ask, actually. OK, let's do something like that. Now, if I reload, OK, this is much better. This looks all right. Now I have 200 and it's going in order.
18:36TEJAS:Before we implement virtual scrolling, I want to show you what happens if we don't, OK. So let's try. Instead of data, what we'll have is mock data. If we go back to where we generated some data here, we'll copy this million element array and assign it to mock data. We now have an index. Sorry, an ID. And this looks good. Instead of data, we'll pass mock data to our component. And now, watch this, we're trying to render a million rows in the browser. So this is why we decided we need virtual scrolling. First of all, that's going to spin trying to get that many objects into memory. And eventually, you -- it'll just fail. So yeah, black screen. Awesome, welcome to the web. And if we wait enough time for it to render, will it, will it not? Oh, decision point.
19:33TEJAS:There's, oh snap, yeah. No shoot, that's the problem. If we go back to data, all good. We have our 200, let's work with this. And implement virtualization. We need mathematics. You see now in this viewport, right, in this window, you see rows 1 through 13. What we want is if you scroll a bit, if you scroll now and the first element is 14, it shouldn't have the same upper bound. It shouldn't end at 200, but 200 plus 14. So whatever you scroll past, we get rid of and whatever -- so the thing in the viewport becomes the first thing, does that make sense? Right? So let's do that with some mathematics. Firstly, what I want to do is limit the amount of TRs to like 20. So let's do const, you know, limit, say 15. And -- let's say 20 just for fun. And we'll immediately return a subset of our data. We'll slice it into limit numbers. So now, yeah, we just have 20. 1 to 20. It's a fixed range. What I want is if I scroll down and now 9 is the first one, I want to get rid of 1 through 8, and I want to have in the window be 9 through 29. I want to remove and add at the bottom. That's the technique we're going for. How can we do that? To do that, we need to respond to the scroll event on our window.
20:57TEJAS:In vanilla JavaScript, you do document, or container.addevent listener scroll. We add it on scroll, we get the event, and we set the scroll top to the events current targets, scroll top. We keep this in memory. This is React because we're using state, but in JavaScript, you can store this in a variable. So we'll do, you know, scroll top and set scroll top is use state of zero. Zero is the default scroll top. And just to make it visible, we'll add an H2 and say you've scrolled past scroll top pixels. So now, if we scroll this, we know how far we've scrolled. Step one, done. Now we need to know how many rows we've scrolled past. There's many ways you can do this for the sake of time. I'm doing the method where you take how much you've scrolled in pixels and you divide that by the height of the rows. Logically, so let's do that -- for that our rows need a definitive height. There are about 47.25 pixels tall. Let's make that Facebook official.
22:07TEJAS:Don't know why I said that. And we'll say the rows are 48 and we'll enforce that with a style attribute here just for safety. This is live coding, things can go wrong. I'm not going to mess around. OK. Now, they get a little bit bigger, but they all have a definitive size. Good. So now, let's find out how many rows we've scrolled past. We'll do const, scrolled past is, ah, co-pilot, I love you. I don't even write this anymore. It's how much we've scrolled past divided by the highlight of the rows. And we do map.floor, otherwise it'll be too precise. For learning, let's see and add this to the DOM, as well. This many pixels or scrolled past rows. So now, yeah, that's working but it's maybe a bit too precise. Math.floor is our friend and we'll wrap that like that. Oops. Cool. And now we know, we've scrolled past these many rows. Phenomenal, now all we need to do is when you've scrolled past 8 rows, remove the first 7 and add 8:00 at the bottom. And logically, we should be there, yes? I've lost all of you. It's fine. You can -- somebody said? Anyway. So let's remove -- in this scenario, if we remove the first 6 and add 6 to the bottom and keep going, we have virtual scrolling.
23:34TEJAS:Let's take a look at that in practice. What we're going to do is where we slice from zero to limit. We'll have it grow. We'll do infinite scrolling first. We'll do past rows, is it past rows? Scrolled past. We'll do scrolled past plus limit. Now, when it's zero, we're going to see zero to 20. But as we scroll, it'll get more and more. Let's reload and see what we get. So scroll and, yeah, we have infinite scrolling now. You can notice, I'm just going to my 200. And you'll notice the scroll bar's getting smaller because the content's getting bigger. In fact, if we look at this in the DOM here, you can see table rows appear. You see that? This is infinite scrolling. And it's pretty cool, except at some point, we'll have way too many table rows and it'll hang and crash and we're almost there. We need to remove the stuff you've scrolled past. To do that, instead of starting from zero, we'll start from scrolled past.
24:31TEJAS:Now, logically, in a perfect world, where everything works right the first time, this should work. Let's scroll and see what happens. And I want you to pay attention to this inspector on the right. Hmm -- some type of dance party happening in my browser. So what's happening there? What's happening is we're slicing the -- when you scroll, we're removing the top, which means what's changing? The scroll top is changing. And when the scroll top is changing, it's removing what you pass, so it changes, adds it back and removes it. That's the flickering you're seeing here. In fact, if you look up on the elements tree, the top note here is being added and removed rapidly because it keeps changing. Another problem with this approach is the scroll bar here lies to you. It's way too long. It's too long for 200 rows. We're about to do what I love doing at work which is solving two problems at once.
25:34TEJAS:We're going to solve the size of the scroll bar to make it tell the truth. And this weird flicker issue. Because both of these windows not being the right size. The table needs to have the height as if it had 200 elements, but at the same time, it needs to not have 200 elements. Mystery. How we do that is using what I call the sandwich technique, because I miss sandwiches. And how it works is, you have your 20 rows. Above that, you add a table row, just a ghost row, that is of height zero in the beginning, but as you scroll past certain rows, this thing's height grows and takes up the size of the rows you've removed. So the height stays constant. Does that make sense? If you scrolled past 1,000 pixels, the first row becomes 1,000 pixels. I call it sandwich because we add a bottom bun, slice, another table row that is the full height of the table minus the window size.
26:33TEJAS:So your scroll container is actually quite large and your scroll bar doesn't lag. I know it sounds confusing, but we'll do this in practice. And I'll show you. I have 8 minutes left, what? So we'll add a table row here, that's our top slice of bread. We'll add our bottom one. And this thing's going to have a height of start row height. That's of course undefined, we shall define it, it's all good. The height here is end row height. Let's define those somewhere up top. How do we compute the start row height? It's the height of all of the things you've scrolled past. So we'll do const start row height is -- exactly, I love co-pilot. It's what -- it's the number of number of rows you've scrolled past times the height of each row. And we'll do end row height similar. Come on, co-pilot. That's wrong. It tried, but failed. It's the number of rows times their height, right? Minus the window size. And also, minus the starting row height.
27:40TEJAS:So this is our formula. So now, if you look over here, we have -- let's reload this page, actually, for posterity. And we have, this is our DOM, we have 22 rows now, right? The first one of height zero, the bottom one of height 9,000, that is our 200 elements, rather. You notice the size of the scroll bar is very small. If we have 200 elements, but we don't. Now, as I scroll, what's going to happen is -- I scroll smoothly and infinitely, or virtually. You notice the number of elements here doesn't change. All right. But what's changing is the start row is taking up all of the height of the ones we've scrolled past. The bottom one is shrinking as the top one grows, and what we have in the middle is the rows we actually want to see.
28:28TEJAS:And we can do this as much as we want. We just keep scrolling and you'll notice over here is that the bottom ones are being replaced on the fly. And there's some virtual scrolling for you. Now, as we scroll up, same thing happens, but the top ones get replaced. Nobody notices, it feels like there's 200, but there isn't. In fact, I can scroll really fast. And it just wow, look at that. In fact, I can grab this thing and go straight to the bottom, oh, that is unintended. Whoa. A little bit trigger happy. I do jump to the bottom and I do get my 200. I need to investigate why it happened after. This actually is great for my ending. Anyway. 200, this works. Let's bring back that mock data. Where we tried 1 million to see what happens. I'm going to get rid of all of my dynamic stuff. Work with just the static mock data here. Let's start with 200 but add a zero. 2,000, what do we have? Let's reload.
29:36TEJAS:Looks pretty smooth. There's still 20 we're doing 2,000. What do I have? I'm getting close to 2,000, yeah. 2,000 there, nice. Let's add another zero, 20,000. Can it handle it? We scroll, we scroll, we scroll. Yeah, we're getting to 20. This bug, I need to investigate that. Whatever. If somebody has an idea, shout it out. You'll get a prize. And lastly, there's 200,000, let's just go 2 million, why not? Can we do 2 million? This is going to take long to allocate the objects and stuff like this. I want to see 20 rows but it's 2 million, can we do it? Yeah, looks pretty good so far. Thank you. And if we just fast track this thing. We're coming up on the bottom here. It ends at 699051. What? That's not 2 million. And then, if I scroll, I'm at the bottom, I cannot scroll more. What is going on?
30:45TEJAS:Someone -- anyone have an idea? OK. Let's try something. Let's maybe -- maybe it's just Chrome. Let's try Safari, what Apple calls the fastest browser in the world. The fastest browser with no PWA support. So let's load this thing and scroll to the bottom here. It seems to work. The bottom is -- whoa. 699051 and some weird layout issues. What's that about? Let's try FireFox. Oh, I don't know, it loads something else, but hard reloads and loads my page. If you work on FireFox, work on the caching issue. And then, same thing, scroll to the bottom and here, it's not even 600,000 -- oh, it's not the bottom. It's even worse, it's like fighting me. What is going on? I don't get it. In the case study of implementing this. I was like, how, why? I've seen browsers behave differently like this in the past.
31:55TEJAS:Fun fact, you know why I don't have any hair anymore, I tore it out with this kind of thing. But I did some research, in this scenario I was frustrated and confused, I did what all of us do. What is that? What is that when you have no answer to your question? Thank you. Who said that? You? You get a prize. Exactly. I stack overflowed. And I found this question. Do the browsers have a maximum height for the body or document? It was posted a long time ago, but it was modified a year ago. I'm interested. The verified answer -- see if you learn nothing in this talk, I don't think you learned that because I didn't know that. There's a limit on the height. So -- and it varies between browsers. In one it's 6 million and whatever, what? And so that is where we find ourselves. How do we solve this?
32:58TEJAS:This is where I tie up the talk. I leave you in suspense. But I want you to know that there's a limit. Now, there's multiple ways you can work around this. Just to appease you. There's an awesome library called AG Grid that is open source, and they don't even use tables, they use divs and make them look like tables because divs you can position absolute. So one hack is you have this massive div and then position absolute top, the top attribute is minus the height and then you have another massive div down there. There's hacks, you can work around it. And this is a hard limitation with browsers. Let's wrap up. Let's talk about what just happened. It started with a need for a lot of data. To have a lot of data but make it feel fast and performant without anyone noticing the illusion. We did that with math, we calculated how many we've scrolled past. And we kept a constant height with the sandwich technique and lastly, we ran into a hard limit in the browser. OK.
34:06TEJAS:With that, I'm going to talk about takeaways. Now, the takeaways I want to talk to you about. This was a technical talk. Not codebased, but culture based. There are two motivations, social and cultural and more technical. And I think they can help the way we've worked. I've put them into practice and I'm sharing them with you because they could help you. Number one, is wake up the wonder. You see, like we, I'm guilty of this where I sometimes will install new stuff without wondering how it works. Without being curious. Smashing Conf's curiosity doesn't kill the cat. There's a lot of cats in Smashing, they're still alive, I think they're curious. Wonder is phenomenal. Just this, how does this work?
34:51TEJAS:I want to implement this myself. I think this is really important in the careers and my career personally. Without wonder, how can life be wonderful? You know what I'm saying? Number two, know your limits. We knew making a database spreadsheet, UI, we knew there was going to be limits and it was important to us to know them before our users found them and complained. So whenever we start something, we try to do our due diligence and that's what we have. And the third one, build or buy? Why not both. I've been around engineering circles enough to have this question. Do we build in house or buy something that exists? Buying is awesome, and I say buy deliberately, because if you work for a for profit company, you should pay for open source, hot take. It's an underfunded, underappreciated type of work. So buy when there's deadlines but I want to encourage building to understand like we did here. Did we learn something? I did. So build and buy, I think, is the key.
35:54TEJAS:And with that Smashing Conf 2022, you've been wonderful. I want to thank you for your time and your patience. Thank you so much. [ Applause ] >> VITALY: Thank you so much, Tejas. Would you like to join me?
36:08TEJAS:Yes. Who wants a unicorn? Can I throw that far? I cannot. Erase that.
36:18VITALY:Yes, it's very cozy isn't it. >> TEJAS: It's close, I want to be closer. This could be the conference. Just casual chats. >> VITALY: Casual chat. We have a fire side, romantic music. >> TEJAS: Food, candles.
36:39VITALY:We had a couple of questions that came up in here. One is, what's wrong with pagination?
36:45TEJAS:Nothing, nothing at all. It's fantastic. You paginate, right?
36:51VITALY:We don't have -- >> TEJAS: It's just tradeoffs. For tables, how do you paginate on a table? It's a single cohesive thing. So we kind of felt like, you know, like people like scrolling. And if you go to a separate page, it can interrupt your scroll flow. So --
37:09VITALY:Another question came up that's -- oh, that's funny, how can you not have a single typo in your code as you were typing it live? >> TEJAS: I've been doing this so long. He said I've been doing this since I was 8. >> VITALY: You've been coding since you were 8.
37:24TEJAS:No, I'm not that young. But I've been doing JavaScript and I started with this may be a hot take in some circles, but my first programming language was HTML. And some people like, that's not a program language, I'm like, we're not friends. [ Laughter ] And then, of course, you find CSS and JavaScript and so on. >> VITALY: Yep. All right. There are a few questions that came up in here, some of them are technical, I do have to ask. That's OK? What if the lines don't all have the same height? >> TEJAS: This is awesome. Whoever asked this, I like you. Because in that section where I said wake up the wonder, I was actually going to give you three things to wonder about as you leave. And one of them is this. How would you do it with variable height rows? You could do something with element.get bounding client to compute the height and compute the height of the things you've scrolled that. You can do that, it's going to be expensive, but that's an option.
38:24TEJAS:That's one way and that's for you to wonder about. But the other way, some of the best like data grid libraries will not even use tables or divs at all but everything's in a canvas. And they have a layout algorithm that looks like a table, it has all of the interactivity, but it's an HTML canvas and the benefit of that is 60 frames per second, GPU driven, battery smooth, that's an option, but there's tradeoffs. Big time accessibility. The tradeoffs with the dynamic heights is performance. You're computing a lot more. And the tradeoffs with canvas is 100% accessibility. And you can do the best you can. You can add ARIA attributes everywhere, but it's not the same as a semantic table. So yeah. Good question. >> VITALY: I think it's just like you've been writing code a long time, of course, but you also have discovered a new friend when you're typing, which would be co-pilot. And I saw a couple of Tweets about I want to try Co-pilot now.
39:18TEJAS:So more general question around that, as well. How do you actually in a bigger team, especially when you get to a bigger team, how do you write better code? And what about keeping the code maintainable over time? Is the only answer -- >> TEJAS: About better code, I don't know what that means. Because better means different things to different people. But maintainable code's a good one. How do you write something maintainable? I try to write things small. React is very popular because it does one job. It doesn't give itself like the angular problem, right? Like factories and services and routers and all of this. No, UI, rendering, done. I do single responsibility principle is a big one. I'm just like, this function does this. I'll name a function, do stuff. So there's no questions about what does this do? About maintainable code, this may be controversial, I apologize if you're a Java developer. But I avoid classes, usually, because a class is like a -- you can have a class human, but what does it do?
40:27TEJAS:I don't know what this does. Can it eat? Can it drink? Versus my alternative that I prefer is single declarative functions that are named after what they do. Verbs. Get data, render data. So then, you can test them, like unit test them and know it's expected this thing does this. So --
40:45VITALY:That makes sense. Another technical question that came up, with virtual scrolling, how would a user copy all of the data from the table? >> TEJAS: That's a great question. When we render, we did data.slice.map. Remember that? We sliced from one index to another, and that's how we did the virtualization. The interesting thing to note there, I'm heavy, I moved this couch. The interesting thing to note there is that we have access to data. We have all of the data memory. With the question being how do you copy all of the data? You could have a JavaScript function, and as an argument, give it your 200 rows. >> VITALY: Exactly. More questions came up. One is how do you see JavaScript evolving? Jamstack has industry around itself. Is it where we are? Is it going to change? >> TEJAS: It has been changing. I think back to when React was introduced today. It's a different universe. Like, there's the evolution of frameworks, like you said, Next.js is evolving fast and it's becoming more of a industry standard. There's an amazing talk by Jeremy Keith about pace layers. Highly recommend watching this. Because it talks about how tech evolves over time and how things become foundational. And I feel like, I feel like React is slowly becoming -- like even now the Chrome dev team is working on first class support for React. So yeah, it's going that way.
42:15VITALY:And I think the future at this point, anyway, or the present is about frameworks. Like Next.js, remix, I think the future's going to be -- what's happening is the level of abstraction is getting higher and higher and higher. And now, I don't know how I feel about this. Tweet at me how you feel about this. There's sometimes engineers who will come in and join my React team but don't know JavaScript but do know React. And I feel like that's awesome that people are finding jobs. But at the same time, it's a bit hard to communicate because we come from this JavaScript first, then React thing. And it's an interesting time in the industry to think about how we navigate this and teach people what's missing and so on. Which makes my job fun because I get to teach stuff.
42:57VITALY:Do you write in J Query? >> TEJAS: I do, yeah. It was a standard for a long time. I think it's the most used library still. >> VITALY: If you look at the data, React is 4%, 4.5%, J Query is 86. >> TEJAS: It's wild. But the reason it's not as hyped anymore is because it just became part of the platform. Document.query selector, more or less, for many reasons can replace J Query. The dollar signs is -- so like, hello. And I think this may happen with React, it could, but I also see another divergence where there's web components that are part of the platform that follow the encapsulation model of React. Yeah, it could go both ways. That's interesting to see maybe the last question here and we can jump into the -- I'm sure there'll be more questions coming to you.
43:56VITALY:So you travel a lot. You do travel a lot. I mean, a lot. How do you make sure you're productive and keep healthy? What are your super tricks? >> TEJAS: Oh, so I apologize, if this is too much. I've been working in developer relations, dev rel for a while. And it sounds fun. It is fun, to be honest, I literally am leaving here and going to another conference. Conferences, usually, there's a pre-party and awesome dinners and socializing and there's a post party and parties and karaoke and music and if you're not careful, you can ship wreck your life.
44:30VITALY:This sounds exciting. >> TEJAS: You travel so much, high adrenaline, high energy, you're constantly excited and talking to new people and you're eating all of this food and drinking all of this alcohol, and that is something I had to learn to have self-control. To have boundaries. Now when I travel, I generally try to avoid alcohol and make certain decisions about how I eat and stuff because it's important. I literally eat a certain way so that my energy levels are constant and not like this. All of it is tailored to having me be happy, healthy and productive. And I'm happy to share specifics of it with you later. But I want to be sensitive to people who have allergies or thyroid conditions. I'm not one to give medical advice. But the tricks to also work/life balance is key. Because in my line of work, I flew here on a Sunday, you know what I mean, you can't work on a weekend.
45:28VITALY:I have to learn and had to learn to keep healthy boundaries, and that is to be able to recognize. This is as far as work goes. This call is sacred -- I tend to want to go the extra mile, usually, and give a lot -- virtual scrolling, unit tests, next level, next level, it's exciting. But I need to learn to say, OK, I've spent an hour, I've run exactly the number of miles I want to well, I'm not going the extra mile because my partner deserves the extra mile, you know what I'm saying? Learning that was a key trick, as well. >> VITALY: That's fantastic. What's the next big thing for you? You have a big goal of where you want to be or get or want to learn? What you want to get better at? >> TEJAS: That's a great question.
46:20VITALY:Actually, I think no. >> VITALY: With virtual scrolling done? >> TEJAS: I'm not saying I'm done with life and I'm not looking forward to anything. But what I am saying is, it's been such a ride. I'm really thankful to be where I am right now. And I find a lot of my friends, unfortunately, are chasing that next thing. I can't wait for this and then I'll be happy. I'm really happy like right now. And whatever comes is going to be awesome, I'm sure. >> VITALY: Well, thank you so much for being with us. >> TEJAS: Thank you.
More talks
- 2026
The Critical Advantage With AI
Agent Conf 2026 - 2026
The New UX
CityJS London 2026 - 2026
Frontend after AI: The New UX
Future Frontend 2026 - 2026
Accessibility panel
Future Frontend 2026 (Accessibility Panel) - 2026
Harnesses in AI: A Deep Dive
AI Engineer Europe 2026 - 2026
AI Yesterday, Today, and Tomorrow: Extending AI Systems with Model Context Protocol
How to Web 2025
Elsewhere
There is every talk I have given, all 84 of them, ConTejas Code, the podcast, Fluent React, the O'Reilly book on how React works inside, and the workshops I teach for engineering teams.