I'm using custom-elements aka web-components within Preact. The problem is that Typescript complains about elements not being defined in JSX.IntrinsicElements
- in this case a check-box
element:
<div className={styles.option}>
<check-box checked={this.prefersDarkTheme} ref={this.svgOptions.darkTheme}/>
<p>Dark theme</p>
</div>
Error message (path omitted):
ERROR in MyComponent.tsx
[tsl] ERROR in MyComponent.tsx(50,29)
TS2339: Property 'check-box' does not exist on type 'JSX.IntrinsicElements'.
I came across the following, unfortunately not working, possible solutions:
I've tried adding the following to my typings.d.ts
file:
import * as Preact from 'preact';
declare global {
namespace JSX {
interface IntrinsicElements {
'check-box': any; // The 'any' just for testing purposes
}
}
}
My IDE grayed out the import part and IntrinsicElements
which means it's not used (?!) and it didn't worked anyway. I'm still getting the same error message.
I've even found a file maintained by google in the squoosh project where they did the following to "polyfill" the support:
In the same folder as the component a
missing-types.d.ts
file with the following content, basically the same setup I have but with aindex.ts
file instead ofcheck-bock.ts
and they're using an older TS versionv3.5.3
:
declare namespace JSX {
interface IntrinsicElements {
'range-input': HTMLAttributes;
}
}
I'm assuming their build didn't fail so how does it work and how do I properly define custom-elements to use them within preact / react components?
I'm currently using [email protected]
and [email protected]
.
Here are the correct attributes to use, otherwise you will get an error when passing key
in for example.
declare global {
namespace JSX {
interface IntrinsicElements {
'xx-element1': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>; // Normal web component
'xx-element2': React.DetailedHTMLProps<React.HTMLAttributes<HTMLInputElement>, HTMLInputElement>; // Web component extended from input
}
}
}
Okay I managed to solve it using module augmentation:
declare module 'preact/src/jsx' {
namespace JSXInternal {
// We're extending the IntrinsicElements interface which holds a kv-list of
// available html-tags.
interface IntrinsicElements {
'check-box': unknown;
}
}
}
Using the HTMLAttributes
interface we can tell JSX which attributes are available for our custom-element:
// Your .ts file, e.g. index.ts
declare module 'preact/src/jsx' {
namespace JSXInternal {
import HTMLAttributes = JSXInternal.HTMLAttributes;
interface IntrinsicElements {
'check-box': HTMLAttributes<CheckBoxElement>;
}
}
}
// This interface describes our custom element, holding all its
// available attributes. This should be placed within a .d.ts file.
declare interface CheckBoxElement extends HTMLElement {
checked: boolean;
}
With typescript 4.2.3 and preact 10.5.13, here is what works to define a custom tag name with attributes:
declare module 'preact' {
namespace JSX {
interface IntrinsicElements {
'overlay-trigger': OverlayTriggerAttributes;
}
}
}
interface OverlayTriggerAttributes extends preact.JSX.HTMLAttributes<HTMLElement> {
placement?: string;
}
Differences:
'preact'
(must be quoted).JSX
.IntrinsicElements
value type is an interface that extends HTMLAttributes.preact.JSX.HTMLAttributes
.HTMLElement
to populate the eventTarget type in props/attrs like event listeners. You could also put SVGElement
if applicable.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With