EPISODE 1871 [INTRODUCTION] [0:00:00] Announcer: Radix UI is an open-source library of React components. Its headless primitives handle the complex logic and accessibility concerns like dialogues, drop-downs, and tabs while leaving styling completely up to the developer. The project emphasizes usability, accessibility, and composability and has become a vital part of modern webdev in part because it forms the foundation of Shadcn UI. Chase Strickland is a software engineer at WorkOS and a maintainer of Radix UI. Chase joins the show with Nick Nisi to talk about Radix, its primitives, Radix's relationship with Shadcn UI, the evolution of web primitives, and much more. Nick Nisi is a conference organizer, speaker, and developer focused on tools across the web ecosystem. He has organized and MC'd several conferences and has led Nebraska JS for more than a decade. Nick currently works as a Developer Experience Engineer at WorkOS. [INTERVIEW] [0:01:13] NN: Hello, and welcome to Software Engineering Daily. I'm your host, Nick Nisi, and I'm joined today by Chance Strickland. Chance, how's it going? [0:01:21] CS: Good. How are you, Nick? [0:01:22] NN: Oh, I'm doing fantastic. I'm ready to talk about Radix, Radix, however we want to pronounce it. But it's a very exciting project. But before we do, why don't you tell us a little bit about yourself? [0:01:32] CS: Yeah, my name is Chance Strickland. I live in San Diego, California. I am a software engineer at WorkOS. And, yeah, working on all of our front-end things and still maintaining Radix as well. That's kind of like my split of the day job. And then outside of that, I have a dog and live with my wife in North Park, San Diego, like I said. And I like to play music. That's a pretty good holistic scripter, I think. [0:01:58] NN: Yeah. What instruments do you play? [0:02:00] CS: I got some drums behind me. Yeah, I don't know. Is this going to be a visual podcast? Can anyone see this? Or is it just audio? If it's just audio, I will make sure I don't make any more visual references. But yeah, I play drums. I've also got several guitars back here. Yeah, I dabble in a few things. [0:02:15] NN: Awesome. Nice. Cool. Well, why don't you tell us what Radix is, or Radix, and how you pronounce it? [0:02:22] CS: I guess, first, we can start by pronunciation, because I've always said Radix, but I hear people all the time will come up and say, "Hey, I love Radix UI." And I'm like, "That's cool." And I don't say anything because I don't actually know if I'm right. The project was started by a team of half Americans and half Brits. Between the accent and potential pronunciation differences between the two, I don't know, actually. I just have always said Radix. [0:02:45] NN: Cool. Yeah, it's kind of got that vite, vite vibe there. [0:02:49] CS: Yeah, exactly. Yeah, you can call it whatever you want. That's totally fine. [0:02:51] NN: For sure. [0:02:53] CS: It'd be more fun if we said it differently the entire time. [0:02:55] NN: I will probably do that, but without even trying. You keep telling me, and then it immediately just goes through my head. But that's okay. [0:03:04] CS: It's totally fine, yeah. [0:03:05] NN: It's a really cool project. Do you want to describe what it is? [0:03:08] CS: Sure. Well, it's actually a few different things. Radix is kind of like this umbrella of a few different projects. The one that most people know about and think about, I think, when they think of Radix is the Primitives. Radix Primitives is a group of composition-first compound components that has been used for quite some time to sort of encapsulate different patterns, common patterns you see on the web that are generally somewhat complicated to implement yourself and customize. Some of them build on top of web primitives, and some of them predate some existing web primitives in some ways, and we could talk a little bit more about that. But, essentially, it's a component library for building on the web. If you need things like a dialogue, if you need a tabs interface, if you need an advanced customizable select drop-down or some other type of drop-down menu, we have all of those components ready to go out of the box. We tried to build them in a way that is as accessible as possible so that you don't have to think a ton about accessibility and also just general usability. We put a lot of work and effort into making the experience very seamless when using Radix components. And we also make sure that they are style agnostic. That's kind of it in a nutshell. And then like I said, we have a few other projects as well under the Radix umbrella. We have Radix Themes, which is also a suite of components, but it sits at sort of a higher level in abstraction. It is completely styled by default and has a themable API so that you can get up and running with your app a lot more quickly without even thinking about styling. And then you can customize it through the themes interface. And then we also have a Radix Colors, which is a very meticulously designed color system for very seamless switching between dark and light mode in a way that is aesthetically pleasing but also designed, again, from an accessibility-first approach, so you don't have to think as much about things like color contrast ratios. And then we also have Radix Icons, which is a suite of icons, as you might imagine. Those are all the projects under the Radix umbrella. But, yeah, most people, I think, are going to associate us with Radix Primitives. [0:05:19] NN: Yeah, I think so. And that's probably how I have come to know Radix as the primitives themselves. But I want to talk about each of these pieces. Let's just start with the primitives there. Is another way to classify them - I guess, would it be safe to call them headless? [0:05:35] CS: Sure. Yeah, I like that term. [0:05:37] NN: Cool. And the way that I came to that term or came around to liking that term was because, on a project I was working on, we were using Material UI and everything kind of looked materially, and we wanted to get away from that and kind of have our own stamp on the design. And Radix Primitives seemed like a really good way to go with that because they really didn't give us any kind of style by default just with the primitives so that we could apply our own. But we weren't missing out on all of the benefit benefits of not developing these components ourselves, and that's in my mind all of the accessibility features and browser compatibility. [0:06:15] CS: Yeah. No, that's absolutely correct. We want to give you maximum flexibility in terms of the presentation of the components, but the underlying patterns should behave similarly across the board across different browsers, different assisted technologies, and how they interface with these things. Those experiences need to be somewhat consistent, but the look and feel is obviously going to be determined in large part by your brand. [0:06:36] NN: Now, it just naturally makes sense to have those primitives and then also to have like a set of designs on top of them or themes on top of them, which gets into the themes part of that. And you said that they're styled by default. So, this would give you like a kind of a natural Radix look and feel if you use those, but then they have a themable API. So, how customizable is it from there? [0:06:57] CS: Yeah, it's pretty robust. You can actually do quite a bit with it. If you go to radix-ui.com, you'll be greeted by the Radix Theme splash page, and there are actually live examples that you will see. It's like a carousel interface where you can reset the theme of the homepage itself, which is kind of neat. But it just sort of showcases some of the flexibility of Radix Themes. Now, that being said, it is opinionated, right? Like any pre-styled library is going to be opinionated. You mentioned Material UI, very opinionated. It tries to strike somewhat of a balance because you do want ultimately to decide some aspects of look and feel. But if you are just trying to bootstrap a project and get it off the ground and don't want to think too much about the styles, Radix Themes is going to look really nice out of the gate. And then later, you can come in and change fonts if you want. Come in and change your primary colors. It uses Radix Colors under the hood. So, you can set a single primary color and get an entire range of colors generated from that, which is quite nice. And again, it just sort of takes away some of the mental overhead of thinking about things like color contrast. And of course, it's built on Radix Primitive. So, again, accessibility is sort of top of mind there, usability is top of mind. All of these pieces play into Radix Themes and as our higher level tool for building apps on the web. [0:08:10] NN: Very cool. I love that, that you can just start with a color and go. Most of the time that's like what you want, at least to get started, is like, "I want the brand color," And mix and match from there, but also have good contrast between text and background and things like that. And so really nice that you can start at any level and get going and then kind of customize to your heart's content. [0:08:30] CS: Yeah, absolutely. [0:08:32] NN: I'm just curious. You've got the themes, which naturally out of the themes would come the colors, right? And icons. How are those picked? What goes into doing this? Because, honestly, this is like something that I can't comprehend, is like picking the right color and then a complimentary color. [0:08:48] CS: That's a great question. And, honestly, it's something I don't really comprehend. To just be completely clear, I didn't build either of these libraries. I maintain mostly primitives. And I do like still maintain these libraries, but the underlying libraries or the beginnings, the origins were not me. And I don't have the meticulous, obsessive-compulsive tendencies to like design an icon suite that is like the way that these things are optimized is actually pretty incredible. Most people don't think of icons as this like really complex thing. But if you want your app to look really consistent across the board, things like line weight, and base sizing, and how each icon scales up to different screen sizes, and how different icons appear in relation to one another, all of that matters a lot more than people realize. Your average person looking at a web app doesn't notice that the icons are slightly different, but they notice something is off, right? They can't pinpoint it, but they know when something looks good and they know when something doesn't look good. And to make the thing look really cohesive and really good, you obviously need a lot of cohesion between the small little details and small elements. And so the icon suite is meticulously designed just for that. It was originally designed by - he no longer works for WorkOS. His name is Colm. And I apologize, Colm, if you're listening. I don't remember his last name. I'm going to have to look it up because I do want to plug him. Starts with a T. But anyway, he and a guy named Vlad on our team, I think, co-designed those. And yeah, like I said, really, really well done. I don't have to really touch them too much anymore, but we do have a couple new icons in the works internally at WorkOS. Anyway, rambled enough about icons. Color system is kind of the same thing. I didn't build that myself either. And again, I probably could if I wanted to sit down and spend that much time on colors, but that's just not what I'm interested in. But it is pretty incredible, actually. It's a lot harder than people realize. And that's kind of a theme with Radix. Everything that we do presents as fairly simple. But then once you peel back the onion a little bit, there's a reason people don't want to do it themselves. It's actually very hard, a lot harder, a lot more time-consuming than people really need to be investing in most cases, when what you really need to be doing is spending time on your product. And so you want tools that help you spend time on your product and not waste time thinking about color scales. And that's really what it comes down to. Yeah, I try and maintain it as best I can. We have some ideas on how to improve both of these libraries moving forward, but the core underlying piece of it, which are the icons and the colors themselves, are mostly sort of baked. [0:11:16] NN: Very cool. And yeah, that's a great point about you can just go down so many rabbit holes on any one of these components and spend so much time there, and that's not actually contributing to the overall product that you might be designing. It's great that these exist for that and give you full customizability in terms of styling, and how it looks, and how it feels. I have so many questions about the primitives themselves. I guess, first, let's talk about what they're made in. Are they React components? [0:11:44] CS: Yeah, everything is built around React. If you use React, awesome. If you don't, I'm sorry, we don't have anything for you. But yeah, they're all React components. We had discussed in the past sort of expanding this and maybe taking like a web components-first approach and then making those extendable so that you could pull them into a framework of your choice. But, ultimately, React is where most of the users are. And it is just sort of like we want to meet the users where they are, and that's our approach. And, of course, at WorkOS, we use React internally extensively throughout our stack. Yeah, it makes a lot of sense for us to stick with React. [0:12:18] NN: Very cool. Yeah, React is definitely where people are at. When it comes to styling, whether it's directly on the primitives or through the themable API within the themes, are they the same in terms of how you would do that? And does that support any styles that you might want to use or any styling frameworks? [0:12:38] CS: Like I said, themes is opinionated. It's also customizable through the themes interface. But my favorite thing about Radix Themes actually is the fact that, under the hood, everything that powers Radix Themes is just CSS. There's no special runtime JavaScript or anything at play to prevent you from styling anything in your app outside of the themed interface. At the end of it, what you do with Radix Themes is you essentially import a few stylesheets. And then once you do that, you have all of the class names mapped to the components you get from Radix Themes. But at the end of the day, it's all just CSS. Overwriting Radix Themes or even selectively including certain stylesheets. We have different levels of abstraction for our stylesheets. So you can only import things that you want from our layout components, like grid, flex components. We have different layout-specific components. If you only wanted those, you can only import that and start building your own color system on top of it. If you want the whole kitchen sink, you import all the stylesheets, but then you can go and you can target overrides. You can reset certain variables that we might set under the hood. It's extremely flexible in that way. Because if you write CSS, you just write more CSS. And because of the cascading nature of CSS, it's not terribly difficult to override things. But we obviously don't necessarily think you should have to be overwriting too many things because that's kind of the point of an opinionated library. But it is flexible in that way. And I think of the CSS-only approach as giving you a very simple escape hatch. [0:14:03] NN: What if you're afraid of the cascade like me and you just use Tailwind? [0:14:07] CS: You know what? That's fine. I don't have anything. How many people do you want to upset in this podcast is the question, I think. I don't know why the Tailwind thing is so polarizing. But use what makes you happy. I will say like Tailwind is at odds with Radix Themes, but they are two different paradigms for solving similar problems in some ways. Or really, I guess, how I would describe it is Radix Themes is half primitives and half something like Tailwind, right? Half of it are the components themselves, which obviously Tailwind doesn't provide. The other half is styling, which Tailwind does provide. And they have two very different approaches to styling. And so I would say if you are using something like Tailwind already and you're using it extensively through your app, it may not be the best fit to then go and grab Radix Themes. But what's great about Radix again is we have other levels of abstraction, and you can go grab Radix Primitives, and then you can slap whatever Tailwind classes you want on any element you want. And at that point, it's just Tailwind's styling. And have a blast with it. We don't really care. I don't really care. Some people care. A lot of people care. I don't know. It's one of the most polarizing topics, I feel like, anytime it gets brought up, which I find odd. As someone who loves CSS and thinks Tailwind is a great tool, I don't really understand the polarization, but - [0:15:22] NN: I agree. [0:15:22] CS: - use what you want. [0:15:24] NN: Yeah, I feel like Tailwind taught me a lot about CSS instead of taking away from it. So, that's good overall. I wanted to circle back to something that you mentioned, which was some of these components predating some web primitives. Can you give an example of one? [0:15:37] CS: Oh, sure. Dialogue is a great example where we now have a dialogue element. That's just a raw CSS element. The Radix Primitive, when we first started Radix, I believe dialogue was technically a thing, but it wasn't super customizable. And I'm pretty sure, at the time, it was fairly buggy or incomplete implementation in probably Safari. I don't remember exactly. But it was technically there in some capacity, but it was not robust enough for you to really realistically be able to use it in a complex web app. And that's also kind of a common theme is that there are cases where certain elements that exist on the web are usable and functional in sort of simple cases, but as the complexity grows and the needs expand, then you might need to reach for something a little bit more customized. And so dialogue's one example of that. Obviously, HTML has a select element that's been around for ages, but we all have tried to customize those and we understand how painful it can be. That is actually changing, by the way. There are new elements that have been introduced in HTML specifically for customizing the select. And that is also really exciting. I can't remember offhand what those APRs are, so I'm going to check that out. But yeah, it's pretty cool what the web can do for you these days, that in the past you would have needed a ton of JavaScript to replicate that behavior. Those are two examples. Yeah, collapsible is another great one. Collapsible just, essentially, being an element that triggers a collapsible section and toggles it on and off. We now have details and summary elements in HTML. You rarely need to reach for JavaScript for that. These things are all still really useful and robust. But, yeah, the web's come a long way in the last several years. [0:17:25] NN: Yeah, for sure. Do you anticipate - I guess when that happens, when the web catches up to something that's existed in Radix for a while, I imagine that it might lead to like - I mean, you don't have to adopt it, I guess, is the answer. But if you wanted to adopt it, would it lead to breaking changes? Or do you just kind of keep your own separate implementation of that? How do you approach it? [0:17:49] CS: Yeah, so it totally depends. That's the answer to every question, right? It depends. But it really does. It depends on a few things. One thing that I always look for in these new web primitives is how flexible and robust are these primitives? In some cases, they may be completely adequate for building the most complex web app that you can imagine. Now we build React components. React generally is something you would want to reach for in a more complex web application context. A little bit more rarely, I'd say. Do you want to reach for it for something like a marketing splash page or a blog? Things that are totally fine to build with web primitives and don't require a lot of advanced use cases, I would say just go with web primitives and save yourself a lot of pain and JavaScript. In more advanced applications like the one that we work on at WorkOS, they're just not always robust enough to handle those cases. And the web is improving on that front. But I still need to check out like - and these web primitives do everything that Radix can do today. If the answer is yes, maybe we could either phase out the component altogether and recommend people use web primitives, or we could build our primitives on top of the web and pull out a lot of our own custom JavaScript that we need to write to maintain really complex logic. It really just depends on what the element is that we're talking about. What are these new web primitives actually capable of? And how much value can we still provide you with Radix? [0:19:16] NN: I want to shift gears a little bit and talk about you and your journey into maintaining Radix. Can you give us that story? [0:19:25] CS: Yeah. Before Radix, there was another React library that was actually fairly similar in its goals and design, and it was called Reach UI. And one of my very early projects - I was a full-time freelancer for several years, and I was working on various apps of different sizes and scales. And at some point, caught wind of this really cool new thing called React that everyone was talking about. Didn't really know much about it. I was just slinging jQuery and CoffeeScript at the time, doing my best with what we had. But there was this really new interesting library that everyone was talking about, and I decided to check it out one day, and I've not really looked back. I've been knee-deep into the React ecosystem ever since. And I don't even remember what year that was, but it was pretty early in React days. I kind of just sank my whole career into that. And as a result, you're building these applications. For me as a freelancer, I was building all kinds of things. I wasn't working on one singular product. I was just sort of helping different teams or helping launch products, whatever the case may be. And so there's a lot of different things that I'm working on week after week. So, I inevitably need to find a lot of different tools to help me do that job efficiently. And over time, React became more widely adopted. I'm starting to see a lot of third-party tools and libraries pop up around React that made my job a lot easier. As time goes on and I'm looking through all of the different tools available to me, I stumble into this library called Reach UI. And it was super helpful. It provided a lot of similar components that you'll see in Radix today. Things like dialogues, tabs, menu, button, drop-downs, that sort of thing. And just little pieces I could grab and stick into my code, and then make them look however I wanted to, and just build my product a lot faster. And that was exactly what I was looking for. What was also really cool about ReachUI was its composition model. And this is something that, really, it's sort of the core behind why React took off in the first place. It's just the underlying composition model of React itself. And Reach UI really leaned into that composition model, and it gave you different pieces of React components rather than trying to stuff everything into a single supercharged component. A library some people might be familiar with from back in the day, and may still be maintained, I don't know, it was called Downshift. This is a really popular library that you would grab, and it would give you the ability to style a complex drop-down select component, right? But it was very powerful, but the API itself was kind of clunky to work with because a custom drop-down ultimately requires that you have a lot of different elements on the screen, right? You're going to have the trigger. You're going to have the list itself, the popover that the list is inside of, the items. And it just sort of gave you this big fat component with a bunch of render props that allowed you to sort of customize things, but it was just really clunky to use. And Reach UI addressed that kind of thing by giving this composition-first API where the root of the component might provide some context to underlying components. And underlying components are directly mapped to one or two different elements. But everything is sort of low-level and composed by passing children through your other components, which that's just how React was modeled in the first place. And so it made a lot of sense to me. And it also really impacted on how I built components in my own apps. The things that Reach UI didn't provide to me, I needed to build myself. But as I was building them, I would think to myself, "How would I build this if I were building Reach UI?" Because that design just made a lot of sense, and it made things really easy to maintain. And so the first component that I remember building that way was an accordion. Reach, at the time, didn't have one. And I needed an accordion for a project. And so I sort of just built it the way that I would imagined Ryan Florence would have built it into Reach. And I just happened to be at a conference some years ago that I popped into React Rally. And at the time, it was still being maintained by Ryan Florence and his business partner, Michael Jackson. And I was chatting with Michael just casually. Not looking for a job at all. I was perfectly happy as a freelancer, but we were talking about Reach, and I was like, "Oh yeah, I use Reach. And it's great. I love it. And I even build some of my own Reach-like components sometimes. And I've got my own little mini Reach extension library that I've been working on." And he was like, "Oh, let's look at it. Let's see it. I want to see what you're building here." I pulled it up. I showed him my little accordion component and how it was modeled. And he said, "Well, how would you like to work on these things full-time?" I said, "Well, that sounds awesome. Why would you want me to do that?" It's a weird thing. We weren't selling it, so I didn't really understand open-source business models at the time. But yeah, they brought me on, and it was a great experience. I got to be the full-time maintainer of Reach UI for a few years. Then the pandemic happened, and the sky fell. The entire funding model of the company behind Reach UI was in-person training, and that dried up very quickly. They unfortunately had to let us go. And I was sort of off in La La Land looking for my follow-up gig. And thankfully, right around that time, a company called Modules was working on this new library called Radix. And they knew what I was working on because they looked at Reach UI a lot for inspiration on the design of Radix. And so, the code that I was writing was very visible to them. And as soon as they found that I was laid off, I basically had an interview within a few weeks because they wanted me to come work on Radix. That was my end there. That was really great. And then, yeah, as one of the early maintainers and builders of the Radix project. And then fast forward to whenever it was that WorkOS acquired the Radix team, I actually went off and worked for a different company and helped build Remix. And then that got acquired by Shopify, and a lot of other stuff happened in my career, but ultimately came to WorkOS, and they were like, "Hey, why don't you maintain Radix again?" And I was like, "That's cool." So, just came full circle. Anyway, that's my spiraling, rambly story about how I got here. [0:25:25] NN: Very cool. Since you mentioned it, I'm looking at Reach UI, and I hadn't used this. I've been around React forever, but I've not used this before. I was immediately drawn to the component component and just looking into what that is. [0:25:38] CS: Oh yeah. That's a funny one too, because component component - well, it's a ridiculous name. But Ryan is kind of a ridiculous person sometimes. I really enjoy his sense of humor. But, yeah, component component was interesting because what it essentially is, this predates Hooks. You can sort of think component component as the way to sort of access contextual logic from parent components and child components before the Hooks world, right? Prior to hooks, there were a couple tricks we had in the React world to essentially implicitly link two different components. And what I mean by that is like the traditional way to feed data from one component to another in React is passing them via props, right? We all just pass props along. But when you have these highly coupled components, like a select, right? A select is always going to be coupled in some way to the thing that opens it, and it's going to be coupled to the list of select items, right? A lot of times, components are just inherently linked together, and props are clunky because you end up having to pass down from the top component down. And, essentially, prop drills, the term we came up with back in the day, where you're just like drilling props to multiple levels. And with highly coupled components, it was just simpler not to have to do that and be able to access contextual data from some parent component. And so there were different patterns adopted for this. There are higher-level components where you could basically create a wrapper function that wraps one component and then just passes along certain props from some parent. And it was fine, but it was a little hard to follow what was actually happening in the code. You would end up with like 20 different higher-level wrappers. And then peeling that onion back became pretty tricky. This was all pre-context. React Context changed a lot of this. But, also, React Hooks obviously changed a lot of this, where you could use the context directly without having to, again, prop drill. But before all that, Ryan decided he was going to try and solve this problem in third-party land, and he came up with component component, which is essentially this higher-level component that allows you to access the life cycle methods of a react class component or state setters of a parent component in children. Yeah, it was kind of like his initial idea of how to solve this problem before Hooks came out and solved a lot of these problems for us. [0:27:52] NN: When I was looking at it, it gave me the vibe of context. That just seeing the set state being passed down is kind of what gave me that, I suppose. But also on the site, I see that it's copyright React Training, which the company you worked, and then they kind of - those folks went on to do Remix, as you said. And you had some run-in with that. And so I have to ask given that this is a React library and Remix's future, as they've kind of started talking about their plans of potentially not going with React for their rendering. I don't know if you had any thoughts or things on that. Just like I think about it in terms of like there's a lot of these mature component libraries now that you won't be able to use if you're using the new Remix. I'm not trying to make you say anything controversial or anything. I'm just curious if you had any thoughts on that. [0:28:42] CS: Sure. Yeah. And I try not to be too controversial. I don't have a lot of hard opinions in this world. I have opinions that are - what is the saying? Strong opinions, loosely held, something along those lines. Anyway, I try to keep an open mind of most things. And same thing goes for this particular thing. Yeah, a little context here. The remix project started shortly after the pandemic when they had to lay the team off, and we're out of work, and they were like, "Well, now is the best time we're ever going to have because we have all this free time. What are we going to do with it? Now is as good a time to like work on this framework that we've been cooking around in our heads for the last several years." Because Remix really was a series of ideas that Michael and Ryan just had but never took the time to build it. And now they had the time. And so they thought, "Why not build it now?" Yeah, started as a React framework and solved a lot of problems that they found lacking in other solutions at the time. Yeah, eventually, I joined the team. And it's a small scrappy little startup trying to work our way to the top. And yeah, we built a framework that caught a bunch of people's eyes, got a good amount of users pretty quickly, and a lot of people really liked the model that we had provided. And they liked it so much that ultimately it was acquired by Shopify. And Shopify has continued to invest in it and build it out. And it's been to a couple different major versions at this point. But as you might know, or listeners may or may not know, at React Conf, I want to say it was last year or the year before, Ryan got on stage and told everyone that Remix was taking a little nap, and the world panicked. Everyone thought, "Oh my god, they're killing Remix. This is like React Router V4 all over again. What are we doing here?" And what he actually meant, it may have been a little clunkily delivered, but it wasn't that they were killing Remix. It was that remix needed to fundamentally change. As much as they really liked the model they had built on Remix, Remix itself as an idea could have been a lot more. But what they didn't want is to pull the rug out from people who were using Remix. They also thought there was still a lot of value in the model that they had, and they wanted to build on that. The thing about Remix, though, is that it was built entirely on top of React Router. The heart of any framework really is the router. And React Router was sort of the underlying tool that powered most of what Remix ultimately was. The entire routing system was React Router. And over time, they started adding new features to React Router that were originally Remix concepts to the point where, at some point, you looked up and you said to yourself, "React Router just looks like Remix." Except there's no server. It's just a client-side library, but the actual APIs look a lot alike. And at that point, what is Remix even? Remix is essentially a compiler that allows you to build a React router app and target a server and a client. Why wouldn't React Router just do that for you if it's already got all the other features, right? And so, essentially, they just ported over everything that was in Remix into React Router and started referring to React Router as a framework because it was. It was suddenly a framework. Superpower framework, and it looked basically the same as the prior version of Remix with a few new major changes. React Router v7 was essentially what Remix V3 would have been. But now you had a naming problem, and naming things is hard in this field of work. You had a naming problem, you had a messaging problem. How do we solve that? Well, again, I go back to the fact that they still had a lot of really cool ideas for Remix. And I just want to be clear about something really quick. I had left the company at this point. So I don't have any inside baseball knowledge of what happened at the point when they decided to do this fork in the road. I'm just making guesses alongside the best of us. I know the guys still, so I know a little bit, but I don't have any special knowledge here. So, I'm just riffing. But what I sort of feel like happened is the Remix name and the Remix idea, the underlying idea, not the implementation, but just the idea of building this web-first framework. That's ultimately what it was. The underlying selling point of Remix from the very beginning was to build a JavaScript framework that really looked like the web. It used web primitives under the hood. It used the fetch API across the client and the server. It used abort controllers. It used HTTP as a design basis across the board. So it really did lean into web-first for principles. And that spirit could still be there in something that they took and just sort of rethought from the ground up. What does the web have on the front end that we're not really utilizing to its fullest potential? Well, it has web components, right? Again, no special knowledge here. I don't know if they're going to build Remix on top of web components, so they may or may not. But this is just me like pondering. What could the web provide you that Remix V1 or V2 didn't provide you? And how can we build on this underlying idea? And the new version of Remix could be whatever that is. And yet, at a certain point, they came out and said, "You know what? We are going to really rethink everything from first principles. We are going to even rethink React." Because while they obviously love React, they built on it, they stake their careers on it, React said - what is it? 10, 11 years old at this point? 12 years old. You said 2013. Yeah, 12, 13 years old, something around there. It's been around the block for a while, and it's still very valuable, but there's a lot of things we've learned since then that maybe there's something they could take forward. And again, no special knowledge. I don't actually know what it is they're going to build. But here's the thing I know about Michael and Ryan is they're always kind of like one or two steps ahead of where you and I are. And every time I've ever doubted them, they've proven me wrong. We will see. I'm very excited to see what they build. And I think they got the chops to build something really cool. So, TBD on that. [0:34:39] NN: Yeah, totally agree. And I think it's great that they're remixing it to use the term and rethinking from first principles. Because if you just settle, then that's what you're stuck with. I'm very excited about it. And I hadn't considered that it could be web components. And not that it is. But if it were - [0:34:56] CS: It really might not be. I don't know what their front-end library of - I do know it will be composition-based because everything - like I said, that's the underlying model that sold React in the first place was composition-first. And so I do know for a fact that they put high value on that. And whatever we see will have a very composition-driven API for building components. I'm stoked to see what it is. [0:35:22] NN: Same. Yeah, I'm looking forward to it. Always good to see new innovation in this. Now, getting back to Radix, I did want to ask about something that I actually don't know a lot about. Even though I've used Radix a lot, when the topic of Radix comes up, inevitably, Shadcn comes up. Can you explain the relationship between Radix and Shadcn, and kind of how that came to be? [0:35:45] CS: Yeah. Shadcn, for those who don't know, is kind of a design system builder or a component builder of sorts where it is a component library that you typically would install from npm. Shadcn originally, when it started, you would go to the website and it would have this giant list of components, and you would click on like a tabs component or something in the docs and it would show you a bunch of code that you needed to copy and paste and drop in your app, which was slightly different approach, right? You didn't install anything from npm. There might be a few underlying dependencies, but it was a copy-paste code approach, which was very old school in that way, which may have seemed counterintuitive. But for something like a component library, it was actually a really powerful idea that you should just own your component library. You should own the code. Because libraries come and go. They may or may not get neglected over the years. There may be limited capacity for you to customize certain things or add functionality. But if you own the code, it's way easier to make tweaks to the code. And for some reason, people are terrified of going into their node modules folder. That's not an option. You got to take it out of the node modules and stick it in your source directory and just own the code. And so that was a sort of novel concept in the React ecosystem at the time. And the ideas just sort of took off. And then over time, it got a lot more sophisticated. They got a lot more components. And then they ultimately built a CLI tool that you could use to just drop the - so you didn't have to manually copy-paste things. You just drop them into your project with a script. And now they have a bunch of tools around LLM usage that I'm not super familiar with. But the relationship that you're asking about is essentially that most of the components in Shadcn are abstractions on top of Radix. Shadcn does provide a lot of other things for you. It's also built on Tailwind. Everything you download or copy from Shadcn is going to be built on Tailwind classes. It expects that you use Tailwind in your project. And yeah, like I said, it's built on top of Radix components as well. If you go and look at like a Shadcn dialogue that's going to be under the hood a Radix primitive dialogue, that comes with a bunch of pre-baked styles using Tailwind classes. [0:38:00] NN: Okay. Could you think of it as like another theme? I guess I'm trying to - [0:38:08] CS: It's a different approach to trying to solve a similar problem as Radix Themes. Yeah. I mean, certainly, Radix Theme's selling point is you want to be able to bootstrap something quickly. You go grab this thing. You don't have to think about styles. And then you can theme it, right? Shadcn does provide a similar interface, except for - again, it's not a library. And the theming options are whatever you are presented with in Tailwind. And then from there, you can sort of manipulate your Tailwind config, and it will impact how all of your Shadcn components ultimately look. But since you own the code, you can also go in and make more granular changes that you might not be able to with a library-first approach. Yeah, it is a different approach to solving a very similar problem. [0:38:50] NN: Got it. Okay. And is there any collaboration between the two teams on these two working together? [0:38:57] CS: Not at all. But if anyone working on Shadcn wants to come help us out, let us know. I've been open to it. But yeah, we're waiting for that phone call still. [0:39:06] NN: Okay. This is making more sense as I've been kind of experimenting with vibe coding a little bit and making an app that is using Shadcn. But then when I go look at my package JSON, it's all Radix. It's because it's using the CLI to just put those components in. We're using Shadcn CLI, but they're Radix components, and then it has their styles and their setup. [0:39:27] CS: That's right. And it's not just Radix. There's other dependencies in the mix, too, for certain components. They come baked with some icon libraries, I think. Yeah, there's a number of other libraries. But, essentially, Shadcn is building on top of other libraries to provide a slightly higher level of abstraction so that you can grab a component really quickly and get off to the races. [0:39:47] CS: Very cool. Where do you see Radix going? Do you have big plans or big changes that you foresee coming? Or do you feel like it's fairly mature? [0:39:58] CS: I think for Radix Primitives, it's fairly mature there. We have a wide adoption at this point. And as we talked about, Shadcn is built on top of it, and it is working very well for a lot of people in production. And there's not a lot more that we really need to build. Now, that being said, there are additional primitives people have asked for and things that we are currently building. There will be new primitives that pop up from time to time. But the overall suite of tools is pretty mature. And so Radix as a whole though - again, Radix is sort of a grouping of different things. It's not just one thing. Primitive is a piece of the puzzle, but there's a bigger puzzle at play. And when you start putting that together, I think the question gets very interesting. What is Radix? What does it become in the future? And the way that we've always thought about Radix is it is a toolkit for building on the web. That's like very high-level how we think about Radix. Everything else from my perspective is an implementation detail. The implementation of what do people need to reach for to build for the web? And I think there's still a lot of opportunity in answering that question, and it's something that we're actively discussing at WorkOS. I think we don't have a very firm answer for that right away. Like I said, it's an active conversation, and lots of really great ideas that we've been noodling on. And we've got some experiments internal that we're working on to try and proof a concept some of these ideas. So, it's very much still baking. All I will say is that the work we're doing, I think, is pretty exciting. And it'll be really cool when we finally get to roll something out to people to see what that might look like. But I think there's still a lot of exploration to do in answering that question. What are the tools people need to build for the web? And how can we provide as much value as we possibly can to fulfill that goal? What that actually looks like, TBD. But that's how I think of Radix evolving over the years. I mean, the web platform itself, like I said, has changed so much, but also how people build with LLMs and different AI tools, basically allowing you to drastically shortcut build times. And so the interface for actually building things with LLMs is very different than how we've done things in the past. I suspect we'll be leaning on that to some degree. But yeah, that's just kind of how I think about Radix. And I think everything that we do moving forward will be in service of that bigger picture. [0:42:24] NN: Very cool. You said that some new component or some new primitives might be coming. What goes into a decision to decide to add a new primitive to Radix? [0:42:34] CS: Sure. Well, we build our entire design system at WorkOS on top of Radix. And so we see very intimately. Our culture is very big on dogfooding. Pretty much any tools that we build for customers, we try and also use ourselves. And that's also true with Radix. Everything that you use as much as possible is built on top of Radix. And so that gives us a really useful insight as to what might be missing. What gaps there are that need to be filled in Radix? And so we can see very quickly what Radix is good at and what gaps there might be. And how can we fill those gaps, right? For example, we're an authentication company for the most part. WorkOS is a lot more than that. But a lot of our tools and services are around authentication. And so as we're building components out for the WorkOS dashboard or the admin portal, we notice that, "Hey, we are reaching for other tools, or we're hand-rolling our own component for this thing." Right? One example being a one-time password field. We've all seen the one-time password field, which is essentially six mini inputs that all accept a single number. And then there are certain behaviors that are expected when you encounter one of these. One of them being if you paste into a single input, it actually pastes in all the inputs. It's interesting because it's really one input. It's just visually six different inputs. But that also kind of comes when you visually alter an input, maybe there's like different user expectations for how things behave than a normal input. So then you have to think about, "Okay, what happens if the user clicks on the fourth input and not the first one?" You have to think about what happens if they focus that fourth input and then they try and paste the code. Do we start from the beginning? Or do we start from the middle? It's weird. Because in a single input, you can't just put the cursor four places to the right. It's one input. And there's only as much space as you've entered white space. There's different things you have to think about when - and this is what I talked about earlier, when you peel back the onion of something that seems very simple. Actually, you have to think about a lot of different things. And so we looked at this and we said, "We don't have this in Radix. Why? Why don't we have this?" It's pretty complex to implement. Well, it would provide a lot of value because tons of apps use this pattern. Let's just build one and put it in Radix. And that's what we did. And so now it's still in sort of like an early pre-release phase. I think the API is still in Flux somewhat. We've exported as an unstable prefix, but it is still documented. So you can go look at the Radix docs today and see our one-time password field. And then we also recently rolled out another auth-related component. Password toggle field, another interesting one. This one was a fun one to build. Also, it looks very simple on the surface. I will say it is a little simpler than the one-time password, but it's still, I think, pretty useful. You've got an input. Everyone's seen this pattern. It's for passwords. I may or may not want to be able to mask the password. You want a little toggle button to turn the password visibility on or off. And so it's fairly simple and straightforward, but you have to think about things like focus management, cursor position when I want to toggle the password on and off, because you don't want to have to keep tabbing back and forth, right? Or if I click on the button, I might not want to move focus to the button because I'm still typing the password, right? Little things like that you want to think about. And we just hide all that logic away. All you have to do is drop it into your code and customize it to fit your needs. And then we have a couple we haven't shipped that are also auth-related. There's another one that I'm working on now that's a password strength indicator. We've all seen that, too, where you've got a list of different requirements that you need to fulfill. And if your password is not at least eight characters or whatever, it yells at you. And as soon as you satisfy that need, it stops yelling at you. We're building that out. And, yeah, we have a couple ideas for new auth-related components. And then there's other non-auth-related components as well. Just any sort of gaps we identify internally. And, also, we get ideas from the community as well. And I know there's lots of components that people in the community have asked us for and we've been not building them for a while. So, we hear you. But all I'll say is we've got some other stuff coming. Keep your eyes open. [0:46:32] NN: Combo box, I imagine, is one - [0:46:34] CS: No. Don't say the word. [0:46:37] NN: I thought that you had a really good explanation as to why that might not be - [0:46:41] CS: This is hard, man. [0:46:43] NN: It's hard. It's hard to do, right? [0:46:44] CS: That's the answer. It's been brought up a number of times. And at this point, we joke about it a lot in our internal meetings. But like I said, keep your eyes open. You never know. [0:46:55] NN: Awesome. Yeah. I just wanted to say on the auth-specific components, particularly the OTP, that field, it is so critical to get that right. Just as a user, if it's wrong, and if I'm trying to - if I mistype something and I have to hit backspace and it's not going back to the previous one, I'm just completely annoyed. And so that is something that is so important to get right. But, also, it's something that's super important to get right, not just for humans, but for machines. And I'm thinking specifically password managers, being able to automatically fill that out and detect when that happens. Now, one password just kind of like fits it in, and it goes. And if that doesn't work right away, that's something that is real friction for real users all the time. [0:47:39] CS: Yeah. Absolutely. And it's not just one password. People use other password managers, and they all have different mechanisms for handling this thing. And so, yeah, we have to test that and make sure it works. And not only works with the password managers, but across different browsers and their password manager extensions. It has to work on mobile. Another thing, if you're on - I'm sure Android has this, too. I use an iPhone. It's probably everywhere. But when I open up a page that has that one-time password input, the second I get a text message, I get a little screen that says, "Here's the code." And then you press that button and the code just autofills and autosubmits. We have to make sure that that works too. Yeah, there's a handful of little features that users expect. And actually implementing them is a little bit more complicated than you might imagine. [0:48:26] NN: Yeah, this is getting into the weeds a little bit, but I'm just curious. Does it come down to it actually just being one field? Or is it like a specific name or specific attributes that might be on that text input? [0:48:38] CS: Yeah, so different people have implemented this differently. The way we do it with Radix is it's actually implemented as six separate inputs. There are a few libraries I've seen that what they do is they have a single input, but then they visually hide it and then mask it with these things that look like inputs. But that sort of constrains you a bit. Because now, it has to - you can only focus at one - it's one input. That input is the thing that always has the focus, right? And when you enter one character and you move over to the right, you have different characters. When they visually look like inputs, you want to be able to see the focus on the currently active input or what I perceive as the input, right? It's a very clever approach. And I think there's actually a lot of merit to building it that way because it does remove a lot of complexity. But there's also some really weird nuances and edge cases that you have to consider. When something looks like something to a user, they expect it to behave a certain way. And trying to mask that behind another element that looks and behaves sort of differently to the user comes with a little bit of potential friction. [0:49:43] NN: Yeah. There is one other question that I wanted to ask. Inevitably, everything devolves in 2025 down to AI. And I'm curious how AI has affected Radix? Or has it? You mentioned it being popular with LLMs, for example. I think a big part of that's probably V0 and Shadcn building components out of that. But have you seen any other effects in this age of AI on how you build these components, or how they're consumed, or how you think about them? [0:50:13] CS: Oh yeah, we think about this a lot. And I would say that the composition model in Radix, I think before we were even thinking about AI, it turns out that LLMs really do naturally work well with composition-first APIs. And so it's really easy to ask an LLM something or go to ChatGPT and ask it for something to build you a React component. And a lot of times it's going to build you something that looks a lot like Radix, because that's just the core composition model of React. And so I think just because we followed that pattern really closely, LLMs are already kind of like naturally good at building things out that either use Radix or look a lot like Radix. But in terms of how we can sort of build on that, yeah, we have a lot of different ideas for that. We want to make sure that you have a cloud config file in your codebase. It sort of helps the tooling understand Radix a little bit more in-depth, understand how you've implemented it in your own codebase. These are different things that we are probably going to add in the near future. They are things that we actively talk about for sure. And then going back to my bigger picture question of what is Radix at the end of the day. A toolkit for building on the web. Okay, how do people build on the web? Increasingly, it's going to be using AI, right? That's only going to increase over time. So, if that's how people build for the web, how does Radix fulfill that vision? Of course, it's going to be AI to some degree. What does that look like? Not exactly sure yet, but it's something that we think about a lot. And again, a lot of ideas that we are currently baking. [0:51:57] NN: Yeah. [0:51:57] CS: I hate being vague about certain things, but I also don't want to say something and people get excited and then it doesn't happen, and they're like, "Oh, you said this thing." I don't know. We're just cooking. [0:52:08] NN: Yeah. No, that's great. And I think that that's enough right now. We don't know where this is all going to go in a year from now. And so, just knowing that it's on your radar as a maintainer and you're actively thinking about how people are going to interact with these tools and how people are going to build using this toolkit, I think that's comforting for sure. Yeah, that's a great answer. Finally, is there anything that we haven't talked about that you want people to know about Radix? [0:52:36] CS: Oh, yeah. One thing we've been doing, my coworker and I, Michael Chan, have been doing a roughly weekly, bi-weekly stream. We're still trying to figure out exact schedule, but we started streaming, and just like what do we do with Radix? How do we work on it? It's very, very new. So, we're still figuring out the format and all that. But it's been a lot of fun. And I think it would be really useful for people to just - if you're really interested in seeing how the sausage is made and peeling back the onion or whatever other food analogy you want to make. But if you want to dig into the weeds of Radix with us, that's your opportunity, I think, to really do that. And, also, even if you don't care about Radix, we talk a lot about like what goes into maintaining a popular open source library, because I think that in and of itself is very useful for people to have context. A lot of us just think of open source as this thing that you get for free, and there's not a real person necessarily behind the screen actually delivering and working on this for you and giving you a lot of value for zero money. I think it's really useful to just sort of understand a little bit more about what goes into it. And, I don't know, maybe give you a little bit of empathy for the folks who are building it. I'm not sobbing about the situation. We're doing fine. But I do think it would be better for the community if everyone sort of like understood what goes into open source. [0:53:51] NN: Yeah, absolutely. I love that level of transparency and just like thought process. Getting into the mindset a little bit is very eye-opening, not just from a maintainer perspective or from a human perspective, but also just seeing, like you said, how the sausage is made or how peeling back the onion, whatever it is. Very valuable just to your own learning and growth. Well, very cool. Chance, where can people find you on the internet? [0:54:14] CS: They can find me on Bluesky is primarily where I spend the majority of my time, though I am trying to spend less time on the internet in general, aside from the time that I work on it. But yeah, chance.dev, which is my website and also my Bluesky handle. That's probably the best place you can find me if you want random thoughts on component libraries, or food, or whatever thought pops into my dumb brain. [0:54:38] NN: Awesome. Well, thank you so much for spending time with us today, and we'll catch you next time. [0:54:42] CS: Yeah, thanks, Nick. This was awesome. [END]