skip to content
Video cover art for Koroflow with Christopher Burns
Video

Koroflow with Christopher Burns

A look at building a robust, customizable cookie management solution in React, covering design choices, branding, theming, testing, and compliance plans

Open .md

Episode Description

Christopher Burns demos Koroflow, his new cookie consent library for React with a Clerk-inspired composable theming system and headless core.

Episode Summary

Christopher Burns returns to share two weeks of progress on his consent management project, now rebranded as Koroflow after a deliberate naming process that prioritized securing the .com domain, social handles, and trademark availability. The conversation traces his pivot from a shadcn copy-paste component model to a Clerk Elements-inspired system where a full cookie banner and consent dialog can be added with just five lines of code. Burns walks through a live StackBlitz demo, installing the package into a fresh Vite React project and encountering real bugs along the way, including incorrect import paths in his docs and CSS normalization issues. Much of the discussion centers on the complexity of his theming engine, a useStyles hook that merges class names, inline styles, CSS variables, and a noStyle flag across multiple component layers while supporting both a singleton all-in-one component and fully decomposed primitives. Burns explains his choice of rslib for building, Vitest with Playwright browser mode for testing, and dependencies like Zustand, Motion, and Radix UI, while noting he may switch to React Aria for better accessibility. Looking ahead, he outlines plans for a cloud-based consent tracking dashboard to achieve full GDPR compliance and discusses using geolocation headers to automatically adapt consent requirements by jurisdiction.

Chapters

00:00:00 - Reintroduction and the Koroflow Rebrand

Anthony welcomes Christopher back after a two-week gap, noting that everything about the project seems to have changed. Christopher explains that the project formerly called Better Events has been renamed to Koroflow, a name he arrived at by feeding Asian, Polynesian, and Spanish-inspired words into DeepSeek and filtering against three criteria: available .com domain, open social media handles, and no active trademarks.

He reflects on lessons learned from his previous startup Everfound, where buying the domain after launch was costly, and shares how "Koro" means heart in Japanese while "flow" evokes the movement of data and consent. Christopher emphasizes that early public communication and building something people actually want have been the driving principles behind his rapid two-week sprint.

00:05:55 - New Website, Fumadocs, and the Shift from Shadcn

Christopher walks through the newly launched marketing website built on Fumadocs with Next.js, explaining how he sourced component inspiration from 21st.dev and customized them to fit his design. He describes staying within the Fumadocs color scheme to avoid CSS namespace collisions rather than layering in separate stylesheets.

The conversation shifts to a pivotal design decision: moving away from shadcn copy-paste components after a first customer's CTO flagged too much code in the pull request. This feedback pushed Christopher toward a Clerk Elements-inspired model where prebuilt, styled components ship by default but can be decomposed down to primitive levels for full customization, reducing the integration footprint to just a few imports.

00:11:55 - The Theming Engine and Style Customization

Christopher details the composable theming system that allows developers to override styles at any level of the component tree using CSS class names, React style objects, CSS variables, or a theme prop passed at the root. He demonstrates the noStyle flag that strips all default CSS, enabling fully custom styling while preserving the component's DOM structure and behavior.

The complexity of merging styles across multiple layers becomes the central topic as Christopher explains how declaring a theme at the top level interacts with class names applied at child components. He acknowledges that the noStyle flag doesn't propagate correctly in all cases and argues this is precisely why he needs a comprehensive test suite before publicly launching.

00:23:15 - Live Demo in StackBlitz

Anthony suggests installing Koroflow into a fresh React project to simulate a first-time user experience. Christopher spins up a Vite React template in StackBlitz and walks through the installation, immediately discovering that the import paths documented on the site are incorrect and that a missing CSS globals import prevents proper rendering.

After fixing the imports and removing conflicting default Vite styles, the cookie banner renders but reveals issues with CSS normalization across browsers. Christopher adds modern-normalize to demonstrate how a CSS reset improves the output, then experiments with the noStyle and theme props live, uncovering additional bugs in how styles merge at the primitive component level.

00:42:11 - Pure CSS Architecture and the Box Primitive

Christopher reveals that all default component styles are written in pure CSS compiled with Lightning CSS rather than Tailwind, a deliberate choice to ease future multi-framework support. He shows the codebase's Box component, inspired by React Native's layout model, which serves as a generalized wrapper that accepts a base class name and theme key, eliminating repetitive div-and-style boilerplate across the fifteen-plus primitive components.

He also discusses the build toolchain, explaining his switch from tsup to rslib built by ByteDance, and walks through the component export structure. The conversation touches on how each component like CookieBannerTitle is simply a Box with a specific theme key, keeping the internal code DRY while still exposing full customization to end users.

00:54:31 - Import Patterns and Developer Experience

The discussion turns to the challenge of structuring npm exports so developers have a clear, intuitive import path. Christopher lays out the tension between a single default import for the all-in-one component versus star imports for the composable version, noting that namespace imports feel dirty and confuse VS Code's auto-import inference.

Anthony suggests options like CLI scaffolding similar to T3 or Redwood's add commands, but Christopher points out the integration is only five lines of code. They agree that presenting one canonical method in the docs while hiding alternative paths is the best approach for adoption, and Christopher notes the added complexity when the consent dialog ships as both a popup and an inline widget variant.

01:05:08 - Theming Tradeoffs and Practical Limits

Christopher and Anthony discuss the tension between maximum composability and simplicity. Christopher explains that his CSS variables allow color, border radius, and sizing overrides without touching React at all, but acknowledges the recursive complexity when themes defined at child levels need to merge upward through context.

Anthony draws a comparison to Bootstrap's notorious difficulty with customization, but Christopher counters that the noStyle flag fundamentally changes the equation. The real challenge is the middle ground: letting someone restyle just one button without requiring the full decomposed boilerplate. Anthony recommends consulting Travis, a CSS specialist, for guidance on resolving the remaining context-merging edge cases.

01:09:47 - Testing Strategy with Vitest Browser Mode

Christopher shows his in-progress test suite using Vitest's browser testing mode powered by Playwright, explaining his choice over React Testing Library because it renders components in an actual browser rather than emulating the environment. He demonstrates a basic test that confirms a component renders and its text appears in the document.

The planned test coverage includes verifying that every primitive component correctly renders children, applies and merges class names and styles, respects the noStyle flag, and passes theme keys through context. Christopher frames testing as the critical gate before a public 1.0 release, acknowledging it as a sign of maturity that he now prioritizes tests over shipping features.

01:22:23 - Competitive Landscape and Dependencies

Christopher surveys existing cookie consent solutions like OneTrust and CookieYes, noting that none offer components that live in the JSX DOM with full customization. He positions Koroflow as the first mainstream consent library to provide composable React elements rather than just hooks or opaque script tags.

The dependency discussion covers Zustand for state, Motion for animations, Radix UI for primitives with a possible switch to React Aria for better accessibility, Tailwind Variants, and Lucide React for icons. Christopher targets minimal dependencies and a roughly 35kB bundle, balancing server-side and client-side rendering concerns, with the widget component being the only SSR-capable piece.

Christopher shares his development workflow using Cursor, v0, and directly pasting files into Claude for assistance. He describes maintaining a Claude context loaded with major privacy legal documents but hitting the context window limit, which leads into a discussion about RAG and vector databases for scaling legal knowledge.

With roughly eighty documents including GDPR articles, CCPA provisions, and third-party analysis, Christopher outlines a vision where the tool could eventually help customers understand regulations. Anthony cautions about hallucination risks, especially where countries have slightly different GDPR implementations, and Christopher agrees that any production legal guidance would need lawyer verification.

01:42:11 - Roadmap, 1.0 Plans, and Wrap-Up

Christopher outlines the path to a 1.0 release within the next week, focusing on polishing components, fixing the test suite, and ensuring Astro compatibility alongside confirmed Next.js and Vite support. The next major milestone after launch is a cloud dashboard for tracking consent in a database to achieve full GDPR compliance, using geolocation headers from providers like Vercel and Cloudflare to adapt consent flows by jurisdiction.

He reflects on the importance of prioritization as a solo founder, drawing parallels to Clerk's years-long development of their elements system and shouting out Hybrid Alex from the Clerk team for inspiration. Anthony offers to help with Astro integration and encourages Christopher to return once the test suite and 1.0 are ready, and they close by directing viewers to koroflow.com and the open-source GitHub repository.

Transcript

00:00:02 - Anthony Campolo

All right, we're live. Welcome back to AJC and the Web Devs with another episode with Christopher Burns. What's up, Chris?

00:00:11 - Christopher Burns

Hey. I would say it's only been two weeks, but so much has happened in such a short time.

00:00:21 - Anthony Campolo

Yeah, it's been two weeks, and you've got a new name, tools, and totally different stuff, it sounds like. So that's really exciting. I'm excited to hear what you've done in the meantime. Why don't you talk about what you built and where you've changed it up since last time?

00:00:40 - Christopher Burns

Yeah. I can hear myself really badly, so I must have a tab somewhere where YouTube is playing something. What the hell? Where's this tab? I can't even see it.

00:01:03 - Anthony Campolo

Do you have another window open somewhere?

00:01:06 - Christopher Burns

No. What the hell? This is something I should have been more prepared for. Ah, found it. Yeah, there we go. I can actually hear myself. Well, not hear myself now. Okay.

So much has changed since we last spoke. As we know, when I last jumped on and we had a stream, it was very much day zero. Well, it was more like day four or five of this idea and building it out. Two weeks later, we have cooked a lot. There's been a lot of changes.

At the time, I was referring to the project as Better Events, because I was going to go down this event system that's still really relevant, but there are some things that we need to tackle first. And then it became this thing where consent was one of the bigger things that kept coming up. So it was like Anthony said, why don't you name it Bear Consent?

[00:02:16] I was like...

00:02:16 - Anthony Campolo

You said that. I said Better Cookies.

00:02:19 - Christopher Burns

Better Cookies. I was like, but it's not all about cookies. And so I went on a Silicon Valley naming...

00:02:29 - Anthony Campolo

A vision quest. A vision quest. Went out to the desert for three days.

00:02:33 - Christopher Burns

Yeah. No, now it involves speaking to DeepSeek about coming up with names.

00:02:40 - Anthony Campolo

So how'd you arrive on Koroflow? What does it mean?

00:02:44 - Christopher Burns

So, Koroflow. Basically, I had some criteria. Learning from lessons in the past, Everfound was a super-easy name. It made sense. It was two English words put together. But one of the things about that was we didn't have the .com early on, so we had to spend X amount of money to buy the .com. And it really sucks when you have to spend X money to buy the .com but then the revenue is like 20 pounds.

So I had basically three criteria: could I get the .com, could I get the social media handles, and were there no active trademarks under the name? All three of those things put together are quite hard to find.

00:03:33 - Anthony Campolo

No.

00:03:35 - Christopher Burns

So I basically started going down this path of, give me Asian-inspired words, Polynesian-inspired words, Spanish-inspired words, and start mashing them together. I had a whole list of ones that I found, and Koroflow was the one that kind of clicked in the end.

You could say it's meaningless, but at the same time a true brand person would say, well, it's always been there. Koro in Japanese is the heart, and flow is obviously like the ocean and the flowing of data. So it's actually like the heart and the flow of consent, of the person and the flow of that consent. You can attach whatever you want to it. I just think it's something unique, something I could just pick and get on with.

Something that's been so important to me since founding Everfound has been taking all those lessons and going a step further and really refining it.

[00:04:49] One of the biggest refinements is communication. Talk about it. Get people understanding it even before you've fully built it. That's like the number one rule. I could go out today and build a dashboard and a whole API service for this that we're going to discuss more, but it is kind of a waste of time as well. Because if nobody wants the first thing that we're going to talk about today and build out, you're almost wasting your time. So very much, that's lesson one of how we've got to this point in two weeks, and we'll go into it.

But the second thing that's massive is, make something people want. Make something you want. And that's really driven me super hard in the last two weeks. Let's start with looking over the website, because obviously when we met last time...

[00:05:55] There wasn't a website yet. There was, but it was very simple.

00:06:02 - Anthony Campolo

Did you start over totally from scratch with this new site?

00:06:06 - Christopher Burns

Yeah. So this is actually quite interesting. What it actually is, is Fumadocs. So Fumadocs is running the whole website in Next.js, and then basically I've attached custom components to the home page of the marketing website, so they leave a space for it. I built out these components for it.

You can say, wow, that actually looks pretty good. I didn't do it completely from scratch. One of the first things that I did with all this was look at inspiration. What is out there for components? In terms of understanding websites, a website that got released recently that I think is really helpful is called 21st.dev. Basically it's got just a bunch of components.

00:07:07 - Anthony Campolo

For design engineers.

00:07:09 - Christopher Burns

Yeah, that's the fancy title that people want to call themselves these days, design engineers. So I looked through and I started taking components and customizing them differently. For example, this one, you can see that it's attached to a scroll. On my website it's completely automatic. So it's taking these examples people have made and tweaking them to what fits best for your website. So that's what I've done. This was actually yesterday's release. Yesterday this website got released.

00:08:02 - Anthony Campolo

So why did you move away from shadcn?

00:08:06 - Christopher Burns

So this is actually, I think, a really interesting subject. I think shadcn is super useful, but currently on this marketing website, Fumadocs has its own shadcn-inspired color scheme and system. So I tried to basically match their styles and just keep it as low down as possible, because I could add a different stylesheet, like a CSS stylesheet for the home page, but then it feels like you're starting to get very complicated with collisions in CSS namespaces.

So at this stage I thought, just put it in their style and basically build it out. What's nice is if I change the Fumadocs theme, it will automatically change it on the home page as well. So it's quite nice that way.

Obviously, since we last spoke, I did have some documentation put together, but it was not at the stage that it's at now. So what's really exciting now is, for example, if I just clear this, what we have now...

00:09:27 - Anthony Campolo

You see the home page, by the way.

00:09:31 - Christopher Burns

Why is that frozen? Weird. I don't know why it froze.

What we have now is this: two weeks ago, I very much took the hypothesis that people would want to put up a cookie banner on their website themselves and use prebuilt shadcn components that they would copy and paste into their code base to customize how it looks and everything.

I was really lucky to have a first customer, a first user. Basically, I put this implementation onto their website. They had changed the style of the shadcn, and so it obviously didn't quite work correctly. So I had to make all these changes. And then their CTO looked at the PR and was just like, there's too much code. Like, there's just too much code.

I really thought about that and thought, but this is what people want. People want shadcn. Give the people what they want. Everyone wants shadcn.

[00:10:49] So I thought, hmm, and started taking it back a level and thought, actually, what about looking at how Clerk does components, thinking about how they create the component tree and then allow you to inject buttons or different props at different levels to customize the theming?

So that's the path that I started going down, and we'll talk about it more. But basically right now, we rebuilt in two weeks a whole Clerk Elements-like system from scratch for a cookie banner that you see here in the corner, but also a full consent dialog where it's completely styled by default. So what you're looking at here is basically five lines of code in the code base now to provide all of this functionality. Pretty impressive.

00:11:55 - Anthony Campolo

Pretty sweet. Yeah.

00:11:56 - Christopher Burns

What I wanted to do was say, hey, but what about if you want to completely customize it? You don't want those colors. You want your own colors. So that's where I started adding the deeper primitives in the code and everything and allowing that customizability.

This is where this whole two-options thing has now come in. We were going with shadcn components, but then it felt very much like adding too much code to their interfaces. So let's remove that, and then all of that React Elements library is backed onto the headless core.

Something that's really important to me, and I did a lot of research on it, we spoke about it before no end, is multi-framework support, and that comes with a lot of challenges. Even two years later, since we spoke about it, Mitosis has come along, but it's still not quite there.

[00:13:10] So I thought I'll build the headless core. So if we want, we can build adapters into a Vue layer, a Svelte layer, a Solid layer, or just the React components at this stage.

So that is a hell of a lot of talking so far. But what we can actually see is this is it. This is now the implementation layer, as simple as three imports. We can talk about that a little bit more. Laying out the consent provider and then adding the cookie banner and consent manager dialog and closing the provider, and then that is it. It will wrap your whole app with this consent management solution. Pretty cool. And so the...

00:14:04 - Anthony Campolo

Cookie banner that just kind of gives you some Tailwind styles, it looks like.

00:14:08 - Christopher Burns

Oh, it's actually better than that. We can go into this and discuss it, and actually we can go over it. What I wanted to take this time today to talk to you about was, obviously this is something that I'm going to be publicly launching later this week. But that sounds weird because I'm talking about it publicly now.

00:14:42 - Anthony Campolo

Already?

00:14:43 - Christopher Burns

Yeah. I mean, just saying I have confidence to put this out there. It's already out there. You can download it today. But like we're going to talk about today, there are some things that I just want to hit a better level on, even though what you've seen already is pretty incredible.

And you're going to laugh, but test suite. I really need to get a test suite in there to make sure that everything is working as expected before I want to publicly push it. Why? Because to me...

00:15:26 - Anthony Campolo

Maybe this works.

00:15:28 - Christopher Burns

Yeah, this is me showing my maturity in the world. For people who are installing this onto their website and, say, they don't update the dependencies very often, I want to make sure that it is a solid version that they're installing at that stage.

So we have basically, so far, a quick overview saying how to get started, what you can customize, and then obviously each separate component and how they work. And what you were saying a second ago, to go back to, was styling.

So this is actually one of the biggest things, and the reason why I want to put a test suite together. Because having confidence in the customization of the components is a complicated matter, no matter what. Because obviously, if the surface area was just this, I could put a test together by saying they just changed the title and they changed the description.

[00:16:53] Really simple. But actually what you can also do is an actual decomposed version at the primitive level. So you see you have root, card, header, title, description, and then all the things that follow it. For example, you may say, I've already got a button style and a card style and a header style, so I want to use my own components in them. I want to use my fancy button for accept.

So that's when you need to make sure that this accept button component, one, accepts and renders correctly a child button, say a custom button. Two, attaches the styles properly. Say if you were to add a class name at this level or a style tag, it passes it through correctly. Three, merging the styles, because as we show here, each one of these components has a style theme tag. And what you can do with that is basically attach CSS. So you could attach a CSS module for a completely custom style.

[00:18:25] You can put class names in, so you can put a class name there. You can use a React style object. So if you want to just customize the style, you can do that completely from the top level, or you can do it at each level down. And it also needs to merge the styles together. And that is obviously a complicated task.

The layer on top of that is this: these components are obviously providing their own CSS as well, and you want to be able to disable all of the CSS that we provide for a completely custom style. So when you go into, say, cookie banner, when you go to style... Oh yeah, sorry. But you can see here, you can pass in a custom class or a React style object, or both.

[00:19:45] Or completely...

00:19:46 - Anthony Campolo

So if you do both, how does it know which one to take precedence?

00:19:51 - Christopher Burns

So that's the browser. What we'll do is we'll merge them both. It'll put the style CSS into the DOM and also the class name, and then it's your browser. I'm pretty sure the style gets overridden by the class names.

So there's that as well. And the other thing here is disabling default styles. So if you want to provide a completely custom style, then you can do that by removing all of the CSS that I've added to these. So it's completely customized, allowing the end user not necessarily to have to worry about the DOM structure or the rendering, but to be able to put in their own CSS or their own button, trying to do it as easy as possible.

Actually creating this system is really trivial and complicated at the same time, because you're just merging class names or styles.

[00:21:21] But what happens when you're merging class names on multiple levels? For example, you declare a theme at the top. So you say Cookie Banner has these Tailwind class names. But then you customize it and you put a class name at this level as well. Is it going to ignore one? Is it going to ignore the other? Is it going to merge them both together?

It's like that whole layer of complexity. And if you then use a theme tag at this level, you need to merge it from the context higher as well. So that's why I need to build a test suite for this, to really make sure that every single primitive component is working as expected at each level: merging CSS, merging class names, removing the default styles, showing the default styles, using a custom button as a child. There's so much that comes into it.

[00:22:35] But I honestly think this is, not that this is a home run on day one, but this is as far as you can go in providing the best cookie banner out there. You can't beat this level of composability. So yeah, it's been a good, long two weeks actually programming this out. And obviously we can look through some code, actually talk about...

00:23:15 - Anthony Campolo

Could you spin up a Create React App or just a fresh React project and then install it in? Because I feel like you're talking about the docs, and someone who comes to the docs, if they just want to try it out, they might not necessarily want to throw it into their actual project. They kind of want to just play around.

00:23:33 - Christopher Burns

You know what? I will admit I've not done that yet.

00:23:38 - Anthony Campolo

We'll have to do it now. But I think it would be...

00:23:40 - Christopher Burns

No, no, no, no. It's on the website. It's on this Next.js website. But actually, that's something that I wanted to do. For example, I know it works in Next.js. I have confidence that it works in Vite. I have pretty much zero confidence in Astro.

00:24:04 - Anthony Campolo

Right?

00:24:05 - Christopher Burns

Maybe. I don't know. These are things I need to test out and build, but if we were actually going to build this in, sure. We can do, let's say... how do people do it these days? Do they use Bolt?

00:24:26 - Anthony Campolo

That's a good question. I mean, I would still just use the Vite React template.

00:24:32 - Christopher Burns

There we go. So let's StackBlitz, and that's...

00:24:40 - Anthony Campolo

That would be a good thing. Also, if you had a link to something where you kind of show a bunch of options in a StackBlitz, and right now we're just seeing the docs. Also, I'm not sure if you're trying to show something else.

00:24:50 - Christopher Burns

Yes. I'm just setting up a StackBlitz. So let's swap this.

00:24:58 - Anthony Campolo

Because I know your last one, didn't you have the code already rendering actually in the docs?

00:25:05 - Christopher Burns

Yeah. So I actually started experimenting with... what's it called? Let me pull it up. There's something I actually started experimenting with. Let me show you. So this is called Kibo UI, and they have a component. Yeah, similar. They actually have a component that allows you to use Sandpack. So they've wrapped Sandpack in an easy component that...

00:25:46 - Anthony Campolo

That's basically CodeSandbox, right?

00:25:47 - Christopher Burns

Yeah, in your code. And I actually got it working and have a preview. Let me actually show... So this was actually something I was looking at today. Let's show you this. So this has this code sandbox in, so you can see that basically it has the code.

00:26:23 - Anthony Campolo

Keep your phone up.

00:26:24 - Christopher Burns

Sure.

00:26:25 - Anthony Campolo

You can make your window a little wider also.

00:26:28 - Christopher Burns

Oh yeah. There you go.

00:26:31 - Anthony Campolo

There we go.

00:26:32 - Christopher Burns

So you can see that it has the code. Yes, it's formatted badly, but basically it almost works. I need to work out why it doesn't. This is just something I need to put more time into.

But this is almost what I see as that perfect version, because you can actually change it to just be a div. But the problem that I have with it right now is it feels laggy. I don't know why. If it's slow to build, I need to do more research into it. But as a concept, it's super cool, being able to just spin the code up in the project and it just works.

Let's see if we could put the provider in. So yeah, the provider works.

[00:27:54] Let's try the cookie banner. There you go.

00:28:02 - Anthony Campolo

Okay. You've got something working. That's interesting.

00:28:07 - Christopher Burns

You can see that it butchers the styling though, but that's because I think it's got no default normalization on it. But as we can literally see as an example, it's pretty cool, isn't it? Being able to literally run the code in the actual browser and it just works. So that's actually something I've been experimenting with today.

But we'll go back to this and go to our trusty package.json. And then what we'll do is we'll add Koroflow slash elements. And we're on beta eight, I think. Let's see if that renders it out. You might have to install. Well, we'll just see.

We'll go to the next stage and then, just like we follow in the introduction, you basically would take them and then put the provider in here, add provider, and then you put the cookie banner and also the consent dialog.

[00:30:16] And then save that. Let's do it this way just to make sure. NPM install Koroflow elements. To be fair, I've not used much StackBlitz as a whole.

00:30:42 - Anthony Campolo

It should work, though, if it works just like in a React project. Usually stuff only gets weird if you're doing back-end kind of stuff.

00:30:55 - Christopher Burns

Yeah, I'm pretty sure it'll work. That is something that needs to be there. So there you go, first bug. The imports are wrong in the docs. Why doesn't it render out? Let's move it into... yeah.

00:31:30 - Anthony Campolo

Yeah, yeah.

00:31:33 - Christopher Burns

Yeah. I don't know how these things work. I'm a Next.js guy. I don't know React. I only know Next.

00:31:50 - Anthony Campolo

The other thing you could try, if this doesn't work, is just getting rid of the app file in general and doing it straight in main.ts. It looks like it's working.

00:32:02 - Christopher Burns

Yeah, let's reboot it. Where's the page?

00:32:22 - Anthony Campolo

Let me try opening it in its own window. If you click the pop-out button. Oh, there you go.

00:32:29 - Christopher Burns

So you can see here straight away that it's actually working, but it's missing something. And that is also something else missing from the initial docs, is you need to import the style.css, or I think it's global. I think I need to check if it's global.

See, this is a perfect example. Just try to run through the docs, act like an idiot, and it gets you there. So let's check. Globals. I was wrong. Globals, not global. There you go.

So just like that, it completely works. There's some major rendering stuff. What this actually is, is the page's styles are overriding it. So as we can see, there's a tag here. So if I just remove all of these styles...

00:34:28 - Anthony Campolo

You also have the app.css styles.

00:34:32 - Christopher Burns

Yeah, no, all of them were fine. Let's refresh that. So this is a good example. What happens if the website doesn't have a global normalizer on it?

00:35:05 - Anthony Campolo

When you say normalizer, what do you mean by that?

00:35:10 - Christopher Burns

Basically it's like a CSS reset.

00:35:13 - Christopher Burns

Yeah. Each browser has slightly different defaults, and a normalizer basically fixes that, if that makes sense.

00:35:29 - Anthony Campolo

It makes it so that the styles actually look the same on each browser, as much as possible.

00:35:34 - Christopher Burns

So it works now. The only problem is, because this is in an iframe, I don't know how to reset the cookies very easily because my browser doesn't work like it does. So we can actually manually do it. I do have a hook in Koroflow. So let me just pull up the docs for testing purposes.

00:36:25 - Anthony Campolo

So right now it's not showing up because you had already selected something.

00:36:29 - Christopher Burns

Yeah, because I selected a consent option, it does what it should do and gets out of the way. So let's make this a little bit better. Let's put a reset component in a TSX file and do a const, then do a reset.

When you're debugging, there's actually a dev tool that would do this easier if I just installed it.

00:37:22 - Anthony Campolo

Which one?

00:37:24 - Christopher Burns

A dev tool that I made for Koroflow.

00:37:30 - Anthony Campolo

Right. Yeah. And you were showing this last time, right?

00:37:32 - Christopher Burns

Yeah. But I have not worked on it in like five betas, so it could not actually work. So I'll just go with this method for now, and then we'll come back to that. So I think we want headless and then... why is that?

00:38:04 - Anthony Campolo

You have to export it, don't you?

00:38:08 - Christopher Burns

Yeah, but I don't...

00:38:14 - Anthony Campolo

Export default.

00:38:16 - Christopher Burns

I know I did. Oh, it's wrapped. That's why. Why is the syntax completely...

00:38:26 - Anthony Campolo

Well, you're not returning it.

00:38:33 - Christopher Burns

Yeah.

00:38:43 - Christopher Burns

Actually, I can just do handle reset.

00:38:59 - Christopher Burns

So I don't know why the syntax highlighting is off.

00:39:08 - Anthony Campolo

Oh, you're not doing import from. You're missing the "from" after consent manager.

00:39:14 - Christopher Burns

That's it. There.

00:39:15 - Anthony Campolo

Yeah.

00:39:16 - Christopher Burns

I just saw that myself. So now, the reason we need to have this as its own component is because you can't call the hook at this level. So it needs to be a little bit deeper. And then we should be able to just pull that in. There we go.

So we see that we can pull it back up. But as we can see there's no default styles. So if I just go onto npm and just pull together this... If I just open another tab and then do npm add... I swear, browsers just never want to work as expected.

00:40:26 - Anthony Campolo

I would just kill the dev server.

00:40:28 - Christopher Burns

Yeah. Okay, so that's because this is not on dev. I think it's only on dev one. If not, we'll just remove that for now. There we go.

So then we can just go into app and do import modern-normalize. If you use Tailwind or any of those kind of systems, it adds one of these by default in terms of the style sheet. So now hopefully when it reloads it should look a little bit better by default.

But it's an interesting question to say, should I provide browser resets in my code? You can see, yeah, there you go. It's reset them now, so it's a little bit better, but still some things are not quite right. You can see the border. More things to look into.

[00:42:11] But this is the thing about the beta, is working this out. And actually this gives a perfect opportunity to talk about the style system. So as you can see, I actually took the method of writing pure CSS for the components. Each one of these is actually pure CSS. There's no Tailwind. It's just Lightning CSS compiling them into a style sheet. Hardcore, right.

00:42:46 - Anthony Campolo

It's probably going to make it easier when you want to incorporate other frameworks that aren't React.

00:42:52 - Christopher Burns

Exactly. And what you can see is, as soon as I provide a no-style tag, so this is what we're talking about, no style, you can see that it completely has stripped all the class names. But there you go. You see that? Not all of them. Somewhere in this style system, it's not quite working right, and I know it.

The only way I'm going to get to the bottom of it is by writing tests. And I'm mature enough to say that, because if I go around trying to hit it like a duck or whatever, I'm just going to blow it somewhere. So I just need to write some tests and work it out that way.

But what you can see then as well is, like we just said about the theme, we can then pass in the object. So let's just give this a reload to get rid of the dialog.

[00:44:04] So what we can see here is you can control it like this. We can say overlay, and then you can see that you have multiple options. Base class name should actually not be there. Base class name is the default class names. So if you do a no style, base class names get removed, but it leaves the class names.

So if you then do like bg-red-500, obviously this isn't going to work because Tailwind is not installed, you can then see, for example, when we go to the overlay, we can see that it's added bg-red-500.

Or you could then do a style where you say background red. And then that puts background red there. But obviously it's not showing because there's no inset. I think it is inset.

[00:45:51] It basically says, wrap it up. I can't remember the class off the top of my head. So we'll do this way a bit more.

00:46:01 - Anthony Campolo

Positioning an element within a containing element. Shorthand property values for the top, right, bottom, and left properties simultaneously. Yep.

00:46:11 - Christopher Burns

There you go.

00:46:12 - Anthony Campolo

So, new CSS today.

00:46:14 - Christopher Burns

There we go. So we can say this has a z-index of two, and then we can say cookie card root, we can say style z-index five.

00:46:38 - Anthony Campolo

That's red for sure.

00:46:40 - Christopher Burns

Yeah. But that should be... let's set background white. Put it in quotes. Why isn't this working? Oh, it's because the position relative display block. There we go.

So you can see how this style system starts coming into play, if that makes sense, where you can basically completely style the DOM however you want.

But what would actually be crazy? I've not fully tried this, so let's see if this actually works. This will be crazy if this works. So if you want to do something like this, where you do cookie accept button, and then you could say, just like we did before, you go back around. There you go. So you can see we can override, but once you go, I want to keep the rest of your CSS, but I actually want to do that cookie button by myself...

[00:48:20] You should be able to pass the no-style tag in and it should work. It doesn't work. There you go. See, this is the point of what I'm talking about. Writing this kind of system to work on these multi-layer complexities, it's actually super complicated. I wouldn't say it's hard, but it's super complicated, because you've got to do this whole merging and resolving of the styles to actually remove the style.

So what that should do is remove all of them, and it should look like that with the no style, if that makes sense. So that's something that I need to fix.

I also have an idea to put the component in here as well. So you could do like button test and it would pass it down as well. But I don't know if that's something I would want.

00:49:35 - Anthony Campolo

It has an A instead of an E in it.

00:49:38 - Christopher Burns

Yeah. This is not actual code, but you know what I mean. Like JSX. You could put a JSX element. So if you want to render just custom buttons but leave everything else exactly the same, you could.

So yeah, super cool. I'm going to have to look deeper into normalizing these styles, and this is a good example of that. But for an interface, what do you think? Is it pretty small, pretty slim?

00:50:20 - Anthony Campolo

Yeah, it seems pretty good. I think what I'm thinking right now is you have a setup where it kind of comes with styles unless you tell it no style. But what if you were to do the opposite? Like it kind of comes with no styling. You just do the components and then you can choose to add in the default styles.

00:50:43 - Christopher Burns

So vice versa. Yes. That's what I was saying about, you would do it this way where you would just set these. But the other idea is to allow you to do this as well. So let me pull this down. Let's pull this into the code.

Yeah, this needs more work, but let's just do it this way to show you. Let's just remove these. This was actually something I wanted to get some feedback on, because so far this whole interface has been done by myself. So now you do it like this, and we have exactly no classes.

[00:52:25] Let's not just pass through this for demo purposes. What you could do, and this is what I was talking about with the normalization, is do things like this where you could also pass no style in at this level and the class names at this level or the styles at this level as well, so allowing you to customize it.

If you want a decomposed version then you could do this version. If you wanted to have all the components be the way that I've defined, you can, but then say actually just this one has no style, or all of them have no style.

Something else you can do is take the cookie button and do this. Let's just define the cookie button. Obviously it will crash because it's not defined in the component. See, this is that thing where I was saying about...

[00:53:50] Some things are not quite set up properly because it's asking you to put in the theme key. So this is where you shouldn't need to do this. The theme key should already be in the component. But this is how it does that matching to the style array.

So what you could do is something like this where you can use your own primitives to wrap the button as well. If you wanted a slightly different button then you can do so.

Trying to explain this theming system is quite complicated. But trying to give as much power to the end user, I think, is really important.

I guess one of my first questions, Anthony, is purely down to this. So let's just define a new file. Right now let's take the typical version of what you need. You need these for imports, right? Correct. Would it actually be better if it was like this in your opinion?

[00:55:31] Like that. Do you think that would be better? As in, one import statement.

00:55:46 - Anthony Campolo

Yeah. I mean, I think the second one is simpler conceptually. I guess my question is, would it make a difference for things like tree shaking and bundle size and stuff like that?

00:55:57 - Christopher Burns

Yeah, and how it allows you to do the passing of the different bits. So if you want it as the root or other things. If you wanted to do the namespace version, you need to do it like this.

So this is where it gets complicated. Let's just take this as pseudocode. Cookie banner. If you do import cookie banner from slash cookie banner, that returns the singleton version of it, the complete version. But then if you do import star as cookie banner, that then says you are installing the composable version. Or you do import cookie banner root from the package. It's that thing where basically how the imports are done changes the components that come out.

[00:57:49] And I don't like it right now. I actually think it's really confusing. If you want the composable version or the built-in version, it starts getting really confusing to me because this syntax is very much like, it's not illegal, but it feels wrong.

00:58:17 - Anthony Campolo

I pretty much never do import star. Yeah.

00:58:21 - Christopher Burns

Yeah. It feels dirty to use the namespace import. So these two feel better, right? But then the cookie banner... there's that classic saying that the two hardest things in computer science are naming and caching, right?

It's one of those things. This is the singleton all-in-one, and this is the composable root. But how do you do this? Because right now you have three different imports because they're being tree shaken from three different folders, if that makes sense: a headless folder, a consent manager folder, and a cookie banner. And you could merge them down, but then it feels like, what's the best developer experience?

00:59:38 - Anthony Campolo

Yeah, because you could also have them each be their own npm package even.

00:59:43 - Christopher Burns

Yeah, exactly. So the current method, it feels like... And what feels worse is this one here is like, under this logic, that works. But then as soon as you go for the consent dialog, it's different because consent dialog falls into two methods. It falls into consent dialog and consent dialog widget.

The reason why is the widget sits directly on the page. The dialog is obviously a pop-up. So technically these should be like that to actually match the same classification as this one, but it starts feeling very much like bundle hell.

So it's something that I need to put more time into and work out the right solution. I don't want it to feel like bundle hell, but I want it to feel like it makes sense how they're laid out and positioned.

[01:01:09] That's one of the last problems I've got to figure out, that and testing the styling configs and making sure everything combines together correctly. But yeah, it's been possible.

01:01:29 - Anthony Campolo

For you to make kind of all these work if you just bundle them in various ways.

01:01:34 - Christopher Burns

Sure, 100%. But then the problem that I think with that is...

01:01:40 - Anthony Campolo

Maintainability.

01:01:42 - Christopher Burns

Maintainability. Also when you're going to put it on your docs, which is the preferred method, is it better?

01:01:53 - Anthony Campolo

Is.

01:01:54 - Christopher Burns

Exactly. But is it better to just say there's one method to do it?

01:01:58 - Anthony Campolo

I think so, yeah, for sure.

01:01:59 - Christopher Burns

And hide the other ones. Be like, you could do it that way, but they're more like hidden paths. Or just not even bundle it that way and just be like, this is the way.

Technically I think you could do it with the namespace root just across the board, but then name the complete component like CookieBanner.Singleton or something like that. But then that feels kind of dirty to put into your JSX. Oh, I want the all-in-one version, so I put CookieBannerAllInOne instead of just CookieBanner.

So these feel like stupid questions, but if you're trying to go for adoption, and I've been speaking to you about this issue, it's like, which one's the right one? And for me to go, all of them work, is not the right answer. Which one is the most logical or easy to understand?

[01:03:00] And also I think something that isn't quite as easy to know is type inference. When you're using these slash namespaces, VS Code, I think, has a harder time picking up the imports.

So if you were to put in the code and then it would say, oh, that's from this package, when I think you're using namespaces instead of having all of them in just slash elements, it would find it quite easy. But when you're doing it in a more high-level way, I think it starts struggling because obviously namespaces are whatever you want to name it. You don't have to name it CookieBanner. You can name it something else because you're saying export everything as this variable name. So obviously VS Code struggles to pick that up.

And I think that's a worse experience for someone like me, who never copies or pastes the imports.

[01:04:13] I always just copy the code in and get VS Code to give me the imports for them. So it's one of those things where the current method is something that I'm not happy with.

01:04:27 - Anthony Campolo

What about how last time we were talking about how with shadcn, you would run a command and it would kind of just throw the code in your project. You could have something like that also, right?

01:04:38 - Christopher Burns

Yeah. So you can actually use shadcn for that even now without actually putting massive amounts of components into your code base, just being like, insert into the right pages.

01:04:50 - Anthony Campolo

It's like T3 or Redwood. They have all those add commands where you just run commands and they would do a quick codemod for you.

01:04:59 - Christopher Burns

Exactly. It's something I'm thinking about, but it's also like five lines of code.

01:05:08 - Anthony Campolo

I would just go to the docs, I would copy-paste the component, and then throw it in. And just however the docs do it is how I would do it.

01:05:15 - Christopher Burns

And the thing is, this is something to also think about. It's really cool providing this theming engine, but how many people are just going to stick the default version in and be like, done, walk away?

01:05:29 - Anthony Campolo

Well, I think the ultimate would be if you could put it in and it would be able to figure out what the styles of your project already are. You've already styled a button and stuff like that. If it could figure out how to inherit the styles that are already in your project without having to write the custom styles again in the component CSS. That's super hard.

01:05:51 - Christopher Burns

Yeah. And to be fair, how I have actually built the button is it uses a lot of CSS variables. So all of the predefined styles that I've written, you can actually change all the colors just with CSS itself. You can override the button color, button roundness, button size purely in CSS variables, so you don't actually even need to do it in React. You can do it in a framework, you can do it in pure CSS as well.

So it's actually a super-hard problem. You say to yourself, I want people to be able to compose this and have it feel like it exactly feels like their app. But then it gets to the point where it's getting too hard, and where do you start putting limitations in? Like recursiveness, it gets super complicated.

Like we're saying, you have the theme at the top level, but what about defining the theme in one of the child routes or deeper and then trying to merge up?

[01:07:07] It's like, no, you either put it in at the root level or you style the class names at each level down and have all of them merge and inherit. Like say if you put class names in at a lower level and then you put the no-style flag at the top level, that needs to be inherited all the way down. So it's actually super complicated.

01:07:31 - Anthony Campolo

Reminded me of what people used to always say about Bootstrap. It comes with all these prebuilt components and styles, but if you want to change it, it's just super complicated.

01:07:41 - Christopher Burns

Yeah, this isn't Bootstrap because you can change it. That's the thing. It's actually super easy to change it because I provide the no-style flag.

It's the middle ground where it's like, I don't want to no-style the whole component. I want to no-style just the buttons so I can put my custom button colors in. And you want to allow them to do that, but also not have to write 50 new lines of code.

Because I think one of the big reasons that I set out to do this theming object is because I didn't want to say it's this simple component if you just want to use everything how it is, but as soon as you want to customize the class name of that accept button, you now need all of this boilerplate to do that. So you want to just be able to say, I just want a new class name at this level and still have that super-simple singular component.

[01:08:51] I feel like it's too much big-brain thinking.

01:08:56 - Anthony Campolo

Talk to Travis because he's super deep into CSS and he built the whole Bedrock Layout thing. So I imagine, at the very least, he would have ideas in this space of how to do some of this stuff. I would guess, out of the people I know, he's the most CSS wizard I can think of.

01:09:14 - Christopher Burns

Yeah. And I think, to be honest, most of it's done. It's just the thing that's happening right now is in terms of the context, and that's something that I need to iron out. But that's why I need to write tests, to make sure I can whack-a-mole in the right direction instead of just all over the shop. We can actually pull it up.

01:09:47 - Anthony Campolo

What library would you use to test? Would you use React Testing Library, or would you want to make the tests more agnostic?

01:09:53 - Christopher Burns

So I actually already have progress on this because I don't do anything by half measures. Let me just go into that git checkout. PR KF-18. Okay, I'll pull my screen up. Sorry.

01:10:59 - Anthony Campolo

Very good. No, this is cool. I think it's really interesting. Like you said, it's very different from what you had last time. I feel like you were really leaning into shadcn, where now it's this whole different kind of system where it's more of a headless-component type thing.

01:11:16 - Christopher Burns

Yeah. So let's pull this up. So this is actually what we were just talking about. You can see the input layer. How it actually renders out right now is, that's where you see it basically exporting each star. So that's how you pull them in.

And then what's actually really exciting is this uses rspack and rslib to do the compiling.

01:11:50 - Anthony Campolo

What is that exactly? I've heard of it, but I really don't know.

01:11:55 - Christopher Burns

So rsbuild, rspack, and rslib are like these alternatives. I think they're made by ByteDance, who make TikTok. They're alternatives to Webpack, and rslib is their simple utility library to compile a library. Because I was using tsup and it's just not fun. Kitze actually wrote a tweet about it and was like, I've wasted 12 hours. What do other people use?

So this is where we actually have this componentry. You see here is where we show the components and you have the cookie banner and some great docs actually. And then you see this is a singleton banner. And then you see this is the CSS. So like I said before, you can customize the border radius, the ease, the width, the shadows.

[01:13:26] You can customize the buttons. Literally everything is overridable. Look at me flexing my CSS skills that aren't Tailwind.

And you see here, you'll actually find this interesting. I took a method from React Native. So in React Native you don't have divs. Divs don't exist.

01:14:02 - Anthony Campolo

Because you have views, right?

01:14:05 - Christopher Burns

You have boxes. And what I had was, this is how we purely do a lot of the layout. So when you have a div with a div inside it and you want to style it, but also you want to replace it, I was like, I have 15 of these components that are basically this div-style wrapper with a different theme tag and a different class name. It's just so much repetitive code.

And I was like, actually, I could do this easier by creating a generalized component called Box and then allowing you to layer the styles on top of it. So when you look at things like CookieBannerTitle, that's just a Box with the base class name, i.e. the default class name, and the theme key to override it with. And you see that that's basically all the way through, instead of having this code in every single one.

[01:15:30] So that's how we do each of these. And you see component ref, this is the button. So passing through the button props, and this is what's going to need testing. Like I said, I actually do have some tests set up already. So I will be using Vitest.

01:15:53 - Anthony Campolo

Yeah.

01:15:54 - Christopher Burns

Vitest.

01:15:57 - Anthony Campolo

Yeah. I mean, it's pronounced vee, so vee-test maybe. I'm not sure.

01:16:01 - Christopher Burns

Tomato, tomato.

01:16:09 - Anthony Campolo

Yeah, totally. Okay. That's what I was going to ask, what you use for tests. The other one would be React Testing Library, which would be the more React-specific one.

01:16:19 - Christopher Burns

So no, I'm not going to use React Testing Library. I'm using Vitest's new browser testing suite that basically is a wrapper on Playwright, so it will act as an actual user.

01:16:41 - Anthony Campolo

So sorry, here they pronounce it Vitest. It's the very first thing on the website.

01:16:46 - Christopher Burns

Vitest, yeah. So this is why I didn't go with React Testing Library, because supposedly, from what I read, React Testing Library emulates the environment compared to Playwright and Vitest's browser mode that actually renders the component and clicks through it.

So literally this is what I'm also working on today. A few hours ago, you can see that it renders the header and pulls the text and says, yeah, it's in the document. So this is what I need to build out basically for every single component. Like yes, it renders the children properly, it does the styles properly, it passes the theme key through properly for each of the use cases.

And it feels like a ball ache, but if you're going to have this composable model, you expect the style system to work exactly the same on every single component. But as you see currently, it's not.

[01:18:06] So the no styles don't get stripped out in certain ways, and it's all because of how I'm passing up useRefs between everything and complicated things to allow you to get to this part. And yeah, it's super easy and it's super not. It's a lot to start killing your brain in all the different directions. So it's fun.

And what's also really cool is we use React Portals to put things on the top level. We also have a flag to disable animation. So if you don't want that smooth version that pops up, you can disable the animation and it doesn't do it.

And we can quickly talk over the actual complexities that we were speaking about. This useStyles hook is my magnum opus.

01:19:16 - Anthony Campolo

Yeah.

01:19:16 - Christopher Burns

It's the thing that is powering all the customizability, but it's also so much pain at the same time.

So the first element is the theme key. Obviously, as you see at the top level, that's what you're going to be overriding the CSS with. The class names are styles. And obviously if you pass in class names or styles, you want it to override deeper. This is where I pass in my base class names that I created.

And this is where it gets fun, Anthony, because you first have to merge the context no style. And if they've put no style on the component, then memoize the style from the theme. Then memoize the new initial style based upon what you're going to be merging into it so it doesn't change. Then you memoize the context.

01:20:34 - Anthony Campolo

You mean memoize?

01:20:35 - Christopher Burns

Yeah. And then you do this thing where you merge the styles, define them together from the high-level theme deeper, and then basically you start returning it.

And it is a lot of code. And the reason there's useMemos is to stop rerendering every time a style or class name changes. Because when you load the component, it's going to render each hook, and the useMemos are trying to freeze it. So it only does it once instead of three or four times.

But yeah, this is my magnum opus. It's complicated, but it's almost there.

01:21:33 - Anthony Campolo

See, it's pretty complicated.

01:21:35 - Christopher Burns

But this is how it's running the ability to do the whole theming element, passing in the theme and all the class names that go with it. And I don't know why that's not working anymore. It's probably because it's like that. Oh, there you go.

So complicated, right? But when this is done, there's never been a cookie banner as customizable as this one.

01:22:23 - Anthony Campolo

What other cookie banner libraries exist? I'm sure there must be some.

01:22:29 - Christopher Burns

Yeah. So there are loads out there and they're at two different levels. For example, one of the classics that we used was called OneTrust, where they didn't even tell you how to implement it into React. And then people created their own custom hook systems to put it into React.

You have things like CookieYes, that's another one. They give basically a hook and that's it. They don't allow you to customize any of the JSX. So actually having your cookie banner in the JSX DOM is something that no other mainstream consent management platform has actually built out. So this is like the first in that area.

And there's loads out there, to be honest with you. But everyone is on the journey to find a good one, especially with all the other things that come with it, like the consent dialog, the controlling of that and the cookies and all those fun things.

[01:23:49] We have a monorepo as well. So everything's out in terms of that. And I think this is all super exciting, but to a normal person, cookie banners and stuff are the most boring thing ever.

But actually it's something that almost every website needs and wants to look slightly different and styled to their brand with the least amount of effort. So providing these utilities has been a lot of work over the last two weeks. A lot of work.

01:24:33 - Anthony Campolo

What's the plan for the next thing?

01:24:39 - Christopher Burns

Yeah. So what's coming up is, obviously, providing the cookie consent banners is only half the solution. To technically be completely compliant with GDPR, you need to track that consent as well in a database to say this IP address gave consent on this date.

So once I've released the first version of this library fully and I feel pretty happy outside of a beta release, that's when I will start building out a cloud solution for tracking that consent externally. So you'll be able to put five lines of code in the code base, put a key into the provider, and leave it at that. And it will handle communicating that consent to a dashboard where you can say, 100% of my users have consented, 50% agree to all, 20% agree to minimum, that kind of stuff.

So that's what's coming next. And there's loads of really other exciting things to build into this space, but I'll leave that there for now. Not that I don't want to talk about it, but it's a lot to build, and I'm focused on getting the first version of these elements out and seeing how people react to them, seeing if people implement them, getting it on people's websites before truly deciding the next thing to build after that.

01:26:21 - Anthony Campolo

Yeah, no, that makes sense. So we haven't actually shared this yet. Just in case people didn't see it, the website is Koroflow with a K dot com.

01:26:35 - Christopher Burns

HTTPS and it will redirect you.

01:26:43 - Anthony Campolo

There we go.

01:26:44 - Christopher Burns

But it's also all open source right now. You can go on GitHub and literally see all of my mad coding.

01:26:57 - Anthony Campolo

Koroflow forward slash Koroflow.

01:27:00 - Christopher Burns

Yeah. To be fair, I've actually started putting some GitHub issues together so people can contribute and actually see the problems and look to fix them.

Because obviously I know there are things in there that are broken or not quite working. But instead of just having it in my head, I should actually put them on GitHub issues. And then if anyone does want to help out or get involved, they don't need to come ask me what they can help with. They can just comment on an issue.

01:27:38 - Anthony Campolo

Your roadmap says 2024 for each quarter. It just needs to say 2025.

01:27:46 - Christopher Burns

That's GitHub's default roadmap tool. I've not even tweaked it that much. To be fair, that is something I was doing just before this. Oh, in the docs? Yeah, the docs, that needs updating.

But yeah, overall we have almost everything there in terms of this. There's just some more polish that I need to do. Make sure that the docs actually work and that the code I'm recommending actually is the right code, as we've seen. Before we started speaking, I said I want you to look over my docs, help me understand them better. And it was literally like, treat it as I'm saying it from day one in a bare-necessities Vite app.

01:28:49 - Anthony Campolo

Yeah, that's the best way to do it.

01:28:52 - Christopher Burns

Not just look at it and think, yeah, I know what that's doing, because actually the code is wrong. Even though I've glanced at it multiple times, corrected it, it's still wrong. So do you have any big questions or anything that you actually want to understand about it, or any of the processes built into it, or anything so far?

01:29:16 - Anthony Campolo

I guess just like, what are the dependencies that you're using?

01:29:22 - Christopher Burns

Yeah, I think that's actually a really good question because part of me thinks it would be great if I could say zero dependencies. Zero dependencies, how great is that?

01:29:39 - Anthony Campolo

That's impossible.

01:29:42 - Christopher Burns

Well, you know you can't.

01:29:43 - Anthony Campolo

Impossible. But it just requires so much work. Just so much more work.

01:29:49 - Christopher Burns

You know the reason.

01:29:50 - Anthony Campolo

Why all of these packages have been written in the Node and JavaScript world.

01:29:54 - Christopher Burns

I'm not going to use a storage solution. I'm going to build my own solution for storage and pulling the cookies and all these things. So there was that level of like, Motion is integrated into the banners. That's what does that smooth pop-up. And then if you pass a no-animation flag, then it uses pure divs.

01:30:25 - Anthony Campolo

Just using Radix UI. Yeah.

01:30:28 - Christopher Burns

So it uses Radix UI currently behind the scenes. To be honest with you, it's not that I'm not sold on it, but I don't know if it's actually compliant enough. And I started with React Aria as...

01:30:55 - Anthony Campolo

That's for...

01:30:55 - Christopher Burns

Accessibility. Yeah, accessibility. But then I wanted to get it out the door faster. So I switched to Radix and shadcn-like components that were more used. But now that I have everything working, I may look at converting it over to React Aria, because one of the massive things about this is accessibility. I really care about screen readers and everything catching the content properly.

And obviously, because it's going on someone's website, if someone is using a screen reader and they now can't access the website because the cookie banner is blocking it, you've screwed over a whole user base from accessing the website. So it's very much something that I think hard about right now.

But current dependencies internally in the elements, it's actually not that big. I think there's only like five or six dependencies. There's Zustand, Tailwind Variants, Motion, Lucide React, I think.

01:32:20 - Anthony Campolo

Lucide React.

01:32:22 - Christopher Burns

It's icons. But I could totally remove that for just two SVGs. It's definitely on the list to get rid of. And then the Radix libraries, where I think I could replace them with default versions.

But literally not trying to go for zero dependency, but trying to go for as few as possible in as many areas to keep the bundles as small as possible. Because I think right now the bundle is around 35kB. Is that bad? Is that good? Some people would say that's good.

01:33:01 - Anthony Campolo

I mean, yeah, it kind of depends what your frame of reference is.

01:33:06 - Christopher Burns

Yeah, exactly. And just trying to keep it really small because obviously you're putting it on so many different websites. Trying not to put as much in as possible, I think, is really important. And also there's that whole paradigm of server-side rendering and client-side rendering you have to worry about as well, and all the fun things that come with that.

01:33:33 - Anthony Campolo

Like right now it's all just client-side rendered, right?

01:33:36 - Christopher Burns

Yeah, except for the widget. The widget can be server-side rendered.

01:33:42 - Anthony Campolo

Okay.

01:33:43 - Christopher Burns

Because that would be displayed directly onto the page by default render. So you want to be able to server-side render that. When the dialog or the cookie banner gets popped up over things, it wouldn't make sense for it to be server-side rendered, but it should be suspensed with a critical tag of like, do this almost straight away.

So yeah, I think it's pretty cool. We shall see with everything where it goes from here. But yeah, in terms of dependencies, in terms of everything, a hell of a lot has been done in two weeks. If someone goes back and...

01:34:36 - Anthony Campolo

Views a whole different project almost.

01:34:38 - Christopher Burns

Yeah. And also a layer of refinement. I spoke to someone yesterday and they literally said to me, it's incredible to see what you've achieved in three weeks. I was like, yeah, completely by myself. Not that I'm saying I'm this cracked 10x engineer, because I make mistakes and all these things. But surprisingly, things like AI are super helpful.

01:35:11 - Anthony Campolo

I was going to ask, are you using any LLMs in your workflow? Are you using like Copilot or...

01:35:17 - Christopher Burns

Yeah, so I use Cursor. I wouldn't say I'm the biggest user of it. I do use it, but I also use v0 a little bit. I also use Claude by literally just copying the files and pasting them into Claude and being like...

01:35:37 - Anthony Campolo

That's what I do, honestly.

01:35:39 - Christopher Burns

Instead of some fancy code integration. I also have a context setup in Claude with all of the major legal documents around the world to give me some better understanding, but I also don't think it's quite good enough.

And something I wanted to talk to you about as well is, what is a RAG and why do I need it for this? Because I definitely need it for this.

01:36:19 - Anthony Campolo

It's just a way... So like what you're kind of doing already, you can give it a bunch of context and it will know.

01:36:26 - Christopher Burns

There's only a limit to the context that you can give Claude.

01:36:31 - Anthony Campolo

Yeah, well with RAG you could put more stuff in and you're not relying on just the context window of the LLM. Or you can go full on with a vector database. And like, how many documents are we talking here? Roughly how much content? How many lines of text do you think it is?

01:36:50 - Christopher Burns

So far I have about 80 documents that are...

01:36:56 - Anthony Campolo

Like...

01:36:57 - Christopher Burns

That's like articles. But this is the other thing as well. It's like using other people's knowledge and what they wrote about it and putting that in there as well to help give a more informed answer. So yes, I want to put in the legal documents, but also legal documents are not written how people understand them. There's papers, there's PDFs, there's websites.

Putting all of that into a context that I can use for myself to make sure what I'm getting knowledge on at this stage is more understandable. But also then to step it further and think about how can this be used for customers as well, in helping them understand the regulations and all these things, because that's really complicated.

And I should caveat that by saying this is only a temporary step. And I say a temporary step because if I actually ever build this into a company, everything that we provide, we will have lawyers back it to make sure it's 100% correct and legal.

01:38:21 - Anthony Campolo

Yeah, because you don't want it to hallucinate or to...

01:38:24 - Christopher Burns

Lie.

01:38:26 - Anthony Campolo

Or something. Or if the laws have changed and some of the blogs or docs or whatever you put in are like a year old and it's just different now.

01:38:35 - Christopher Burns

Exactly. And for example, AI could so easily hallucinate on GDPR because different countries have slightly different versions of the regulation, and it could quite easily hallucinate between merging the UK with Germany, which have slightly different laws around GDPR. So it is different as well. Or like, say for example, California CCPA versus Utah's versus Delaware.

01:39:08 - Anthony Campolo

This is what I'm talking about from last time because you had, in your dev tool, a couple of those options in there. And if you are able to actually bake all that into your tool, that's one of the things that would really give it a lot of value for people.

01:39:21 - Christopher Burns

Yeah. And something I think I can do that would be really powerful is if the provider, the host, could tell the app where the user is and provide different options for the cookie banner. So basically, if the hosting provider could give a header that was like, they're in California, be like, oh baby, you're being locked down. But if they're in, I don't know, Africa and they're in Egypt, be like, they have no privacy laws, do nothing. They use like the...

01:40:06 - Anthony Campolo

IP address to basically kind of roughly figure out someone's location, granted they're not using a VPN.

01:40:13 - Christopher Burns

Yeah. So you could do it that way, where the front end would call an IP service, then return the location. Or you could do it where if someone uses something like Vercel or Cloudflare, that gives the headers of where they are, just passing that through. Some providers already give their headers to the users. Google, AWS, Vercel, Cloudflare. They will actually pass the headers down if you ask for them.

But yeah, it's one of those things where there are multiple methods. But I think the key here is trying to keep the interface at five lines of code for as long as possible.

01:41:04 - Anthony Campolo

Right. Yeah.

01:41:05 - Christopher Burns

To not even say, I want to worry about GDPR or CCPA or whatever, and just say you trust us to do the right thing in each jurisdiction. So if someone comes from X or Y, we know what to do. Because I think the more you start customizing and optimizing that compliance level, the more you need to know, and then you start getting into the foot-guns of GDPR and CCPA.

If you can keep it as pure as that simple component and then say you pick all the right things, I think that's the key to actually really taking off in this area. Saying to developers, we know you need this, but you've been putting it off because you don't want to know about this stuff. So you remain blissfully ignorant, put these five lines of code in, and call it a day.

So yeah, there's so much that has gone on so far and it's really exciting.

[01:42:11] But over the next week, I should be able to polish up the components, get them all working right, and then I will not even go for a beta. It's currently in beta, it's just a soft beta. I would just put the 1.0.0 out there and say it's ready to go, it's usable in all states. And we'll go from there. So super exciting. A lot has changed in two weeks.

01:42:47 - Anthony Campolo

Yeah. Well, let me know once it's official and I'll tell people about it.

01:42:55 - Christopher Burns

Yeah, 100%. I guess the only last thing to say is anybody watching, or anyone who wants to talk to me about it or beta test or have conversations about it, please do. You can reach out to me on literally any platform. It's still just me working on it, and it might always just be me working on it. We'll see. But it's really exciting no matter what, and we'll see where it goes.

01:43:31 - Anthony Campolo

Just in case people need it and find you. Yeah, .com forward slash scripts.

01:43:38 - Christopher Burns

Or x.com slash. And you can follow the Twitter. Yeah, super interesting. I'd love to hear people's opinions on it and everything altogether. I'm super excited about where this is going.

01:44:02 - Anthony Campolo

Yeah, man. A lot of great work here. Super cool. I'm excited. It's cool to get to see the thought process and how you're building it out.

01:44:12 - Christopher Burns

Basically a scattergun. It's like how I kind of imagine it in my head. I think I've got a lot more refined over the years, but it's a bit like a shotgun. When I started, it was like a shotgun but the spread was still super massive. I think over time I've managed to tighten that. But it's still a shotgun. It still spreads across the board, and it's like, have you thought about this? And it's like, yes, I've got 50% in that direction and thought, this is not going as easy as I want it to. I'm going to drop this for now, go do something else.

And we see that with the Sandpack example. It's super cool that it works in the website. It just wasn't getting that really quick implementation. And that's what I've really been focusing on over the last few weeks, trying to do the things that are complicated and hard but also easy and simple, and trying to work out what actually needs to be done.

[01:45:20] That's complicated and hard. And then everything that doesn't need to be done that's complicated and hard, moving that to another day instead of just saying, why are you spending so much time on something that's really hard?

And the Sandpack example, if it worked, it would be great. But it's also down to that. If I spent a week trying to fix that to get the perfect implementation, at the end of the day people are just going to copy and paste it into their app. So does it really need to render on the website? It'd be nice if it could, but also they're just going to copy and paste it into their app.

So it's finding that balance. And I think that's a really hard skill that I've refined a lot on in this founder journey, you could say.

01:46:15 - Anthony Campolo

Anyway, it's all about prioritization because you're just one dude with only so many hours in the day.

01:46:21 - Christopher Burns

Yes. And I think what I've achieved so far in two weeks, the new website, the docs, the actual components... not that I want to flex or anything, but I have a lot of appreciation for what Clerk had built out. They spent years making their first version, and then they said, we're now going to make these new Clerk Elements. And they had already tons of components: the sign in, the login, the drop-down. I've just been doing that for two components, and I feel like I'm hitting their level of quality and I feel really proud about that.

But also a massive amount of respect, because actually having this as an API infrastructure is super complicated. And there's somebody I'll shout out here, Hybrid Alex. He currently works on it at Clerk.

[01:47:36] And yeah, looking through their code, understanding how they've done things, super interesting. I have different implementations for the theming engine and stuff, but just seeing how they did it to take inspiration and reference, I think, is really cool.

01:47:58 - Anthony Campolo

Hybrid underscore Alex, if you want to find them on... Yeah.

01:48:02 - Christopher Burns

He builds out the... He's on the Clerk team currently and builds the Clerk Elements. So these are Clerk's components. Obviously that's a big inspiration, but a massive amount of work to achieve.

But I think we're almost there. Just need to whack-a-mole with tests. And I never thought I'd say that. I've never been a person that's like, you know what, now is the time for tests. But with this...

01:48:49 - Anthony Campolo

Yeah, if you're building a library, you just have to. You can't get away from it.

01:48:55 - Christopher Burns

Sooner or later things are going to break or not work as expected, and debugging it is hard to some extent.

01:49:06 - Anthony Campolo

Well, maybe once you get more tests written, you can come back again. We can take a look at that or whatever you end up building next. Or once you just kind of get the whole API surface figured out. Yeah, it seems like things are still kind of in flux, but you're mostly there.

01:49:22 - Christopher Burns

Yeah. And I have a lot of respect for people that spend a lot of time thinking about interfaces before actually writing them. Sometimes I feel like, I was having a discussion about the imports, it's like you could sit there and really think about it, or you can just implement it and see if it's right.

And that's what this beta period is, just breaking it, changing it. I wouldn't expect anyone to implement it while it's in these breaking betas. But that's why we're breaking it fast, moving it, polishing it. And then when I feel confident, that's when we put out the 1.0 and say, everyone, this is the brand-new level for cookie banners across any React projects.

I will need to make sure it works on Astro before launching it though. That's a massive...

01:50:21 - Anthony Campolo

I can help you with that. It should just work.

01:50:25 - Christopher Burns

It should just work, right? It's just a React component.

01:50:29 - Anthony Campolo

Yeah, but once you start putting React components on an Astro page, stuff can go weird, especially if you have CSS involved. So I can see how you'd get weird random edge cases.

01:50:43 - Christopher Burns

So what you're saying is I need to build a React version of my elements package.

01:50:51 - Anthony Campolo

I mean, it kind of depends. I think that if you just lean into the React, then you're mostly just going to have to figure out how to get it to work with Astro. And that's more about how do you have an Astro project that is setting up the JSX in a way where nothing weird is going to happen.

01:51:13 - Christopher Burns

Yeah. And I thought about using Solid and all these things, but I don't want to be obtuse when I say this. While every other framework is doing some really cool and important things, React is still the baseline by a massive margin. And it's already been hard enough building it out in React.

And no, I don't think it would have been any easier in other frameworks as well, because what I'm doing is not really framework-specific. I would like to see, once I have it to a point where I'm happy with it, actually let's give Mitosis another look. Because you're looking at a finished JSX DOM tree instead of trying to build it out as you're trying to do it. Be like trying to replicate the JSX DOM tree, the hook structure in Mitosis and seeing if it actually renders out to the other frameworks, or Solid for example.

[01:52:24] But that's another thing for another day. Not today.

01:52:31 - Anthony Campolo

Awesome, man. Yeah, we can start wrapping it up. This is super fun, man. Thank you for sharing all this. And hopefully we can get you back on next time you have another huge code dump to share.

01:52:43 - Christopher Burns

Yeah, maybe in another two weeks.

01:52:46 - Anthony Campolo

Maybe. You're moving fast.

01:52:49 - Christopher Burns

Exactly. Well, there's no time like the present. Awesome. So let's wrap it up and we'll catch everyone soon.

01:53:02 - Anthony Campolo

All right. Thanks, everyone, for watching. We'll catch you next time.

01:53:06 - Christopher Burns

Bye-bye.

On this pageJump to section