Adding Custom Elements to JSX.IntrinsicElements
The first step is to explore React's typings and find
You can use VS Code locally to navigate through or view the
IntrinsicElements interface on GitHub if you are using the online Stackblitz editor.
The interface includes key-value pairs that represent different elements
0:00 Let's give it a go. We have custom-solution-element here. We first need to dive into React typings to see if we can understand why JSX.IntrinsicElements even lives. If we go into React, I'm just going to have to...Here we go. In fact, we get a freebie here, where we've got K in keyof JSX.IntrinsicElements. I can-command click on JSX.IntrinsicElements. I end up inside here. Wow.
0:31 We have a, abbr, address, area, article, aside, all of the different types here that represent all...Well, what are they representing, actually? Because it looks like here we have a key. Then we have something. That something, it looks like it's the props of those attributes or the things that a takes here.
0:56 React.DetailedHTMLProps. AnchorHTMLAttributes. DetailedHTMLProps -- oh boy -- that looks a bit intimidating. AnchorHTMLAttributes, these are the actual props that that element actually takes itself.
1:10 This IntrinsicElements thing, if we can add a new element to this...In fact, let me just try this. I'll do this. Now if I just add custom-solution-element -- here we go -- and then let's say it takes a wow boolean. Now, property wow is missing here. We've got wow is...Let's just say it's 1.
1:40 Nice. It doesn't take children. Here we go. What if it takes children? Which is like React.ReacNode, for instance. Beautiful. Then wow, which is boolean. There we go. We've also got some nice required props here. That's cool.
2:01 How do we add this in, inside this file? Because currently I'm just editing the raw index.d.ts files. Let me delete that. We're inside an interface, which is IntrinsicElements, here. Let me pull this over. Whoops. Don't save.
2:21 We've got our IntrinsicElements. This is inside namespace JSX. We know, from JSX namespace, that we can basically say, "declare global namespace JSX," and then append to this interface of IntrinsicElements. I definitely don't want to save those changes. Let me go back to the file where I was.
2:43 Inside here, I can say, "declare global namespace JSX." Then I can say, "interface IntrinsicElements" -- in fact, Copilot is giving the game away here -- and "custom-solution-element." Look at that. Beautiful, beautiful stuff.
3:03 Hang on. Looks like I've accidentally saved this little piece of code. What we can do here is we can say, "interface IntrinsicElements custom-solution-element."
3:14 Does not exist on type JSX.IntrinsicElements. Did I mess that up somehow? Intrisic. Oh gosh. IntrinsicElements. There you go. You can see how painful this declaration merging is. That's a nasty little typo in the middle there that I didn't figure out.
3:31 Now we've got an empty object here. We should probably say that children is possible here, so React.ReactNode. That's nice. Now I can add a required prop if I want to, so requiredProp string. We get requiredProp, blah, blah, blah, blah, blah, blah. So beautiful.
3:46 This is really cool. It's nice to be able to do this sort of deep diving into external libraries, append to globals, and get a sense that we can mess about with this stuff and make some changes. Well done if you found this solution.