µce is a tiny helper library to create Custom Elements. This starter kit helps to set up a project using µce together with TypeScript.
- Written in TypeScript
- Bundled by Rollup
- Optionally use PostCSS for styling
- Includes polyfills to support older browsers
- Tested on Internet Explorer 11
Live examples on CodeSandbox (which is using Parcel instead of Rollup).
Typed Custom Elements can simply be used in a React project. For example:
import React from "react";
// Import the uce Custom Element (which activates it with tag "my-counter")
import "./my-counter";
export const App = () => {
return (
<>
<my-counter />
<my-counter count="99" />
</>
);
};In order to preserve typing, "my-counter" is listed in globals.d.ts (which is included in tsconfig.json). This also solves the TS error "Property 'my-counter' does not exist on type 'JSX.IntrinsicElements'" (raised because React JSX elements must be written in PascalCase).
To include "my-counter" to the accepted tags (and to add the types), take these steps:
- Create a type definition file
globals.d.tsin the root of your project:
// globals.d.ts
import type { MyCounterProps } from "./src/my-counter";
declare global {
namespace JSX {
interface IntrinsicElements {
'my-counter': MyCounterProps;
}
}
}- Include the type definition file in
tsconfig.json:
{
"include": [
"./src/*",
"./globals.d.ts"
],
"compilerOptions": {}
}For Mithril, you can preserve typing by using a thin wrapper component around the Custom Element:
import m from "mithril";
import { MyCounterProps } from "./my-counter";
// Import the uce Custom Element (which activates it with tag "my-counter")
import "./my-counter";
export const MyCounter: m.Component<MyCounterProps> = {
view: (vnode) => m("my-counter", vnode.attrs)
};and then use the wrapper component:
import m from "mithril";
import { MyCounter } from "./MyCounter";
export const App = {
view: () => {
return [
m(MyCounter),
m(MyCounter, { count: "99" })
];
}
};Alternatively, use a wrapper function:
const customElement =
<Attrs>(tag: string) =>
(attrs?: Attrs) =>
m(tag, attrs);
const myCounter = customElement<MyCounterProps>("my-counter");
export const App = {
view: () => {
return [
myCounter(),
myCounter({ count: "12" }),
];
},
};my-counter-postcss is styled with CSS Variables that are defined in the element's CSS definition. However, this does not work for IE 11, that only accepts CSS Variables that are defined in :root - see my-counter-postcss-ie11.
If you must support Internet Explorer 11, you have two choices:
- Always define CSS Variables in
:root(which is the document root). If you're not careful, variables may be overwritten - alternatively use a single root file for all definitions. - Use PostCSS plugin postcss-cssnext (deprecated) to process all CSS Variables to static values. However, as expected, this does remove the option for theming by simply changing CSS Variable values.
The example component is a simple (and slightly modified) counter that is used on webcomponents.dev to compare Web Component libraries.
- Clone this repository
cd uce-starter-typescript-rollupnpm install
npm run dev- runs the dev server on port3000npm run build- createsbundle.jsindistnpm run serve- runs a server ondist