Package Exports
- preactement
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (preactement) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
preactement
Sometimes it's useful to let the DOM render our components when needed. Custom Elements are great at this. They provide various methods that can inform you when an element is "connected" or "disconnected" from the DOM.
This package (only 1KB GZipped) provides the ability to use an HTML custom element as the root for your components. It's intended to provide an easy way for you to integrate Preact into other server side frameworks that might render your HTML. The exported function can also be used for hydration from SSR in Node.
Getting Started
Install with Yarn:
$ yarn add preactementInstall with NPM:
$ npm i preactementUsing define()
preactement exports one function, define(). This allows us to register a custom element via a provided key, and provide the component we'd like to render within. It can also generate a custom element with props ready for hydration if run on the server.
The first argument must be a valid custom element string, e.g hyphenated. If you do not provide this, a prefix of component- will be applied to your element name.
In the browser
In order to register and render a component, you'll need to call define() with your chosen component, e.g:
import { define } from 'preactement';
import { HeroBanner } from './heroBanner';
/*[...]*/
define('hero-banner', () => HeroBanner);This registers <hero-banner> as a custom element. When that element exists on the page, preactement will render our component.
If the custom element isn't present immediately, e.g it's created dynamically at some point in the future, we can provide an async function that explicitly resolves your component:
define('hero-banner', () => Promise.resolve(HeroBanner));This allows us to reduce the overall code in our bundle, and load the required component on demand when needed.
You can either resolve the component from your async function, as seen above, or preactement will try to infer the export key based on the provided tag name. For example:
import { define } from 'preactement';
/*[...]*/
define('hero-banner', () => import('./heroBanner'));As the heroBanner.ts file is exporting the component as a key, e.g export { HeroBanner };, and this matches the tag name in snake case, e.g hero-banner, the component will be correctly rendered.
On the server (SSR)
You can also use define() to generate a custom element container if you're rendering your page in Node. When wrapping your component, e.g:
define('hero-banner', () => HeroBanner);A functional component is returned that you can include elsewhere in your app. For example:
import { define } from 'preactement';
/*[...]*/
const Component = define('hero-banner', () => HeroBanner);
/*[...]*/
function HomePage() {
return (
<main>
<Component />
</main>
);
}Properties
If you're not running preactement on the server, you have several ways of defining props for your component.
1. Nested block of JSON:
<hero-banner>
<script type="application/json">
{ "titleText": "Hero Banner Title" }
</script>
</hero-banner>2. A props attribute (this must be an encoded JSON string)
<hero-banner props="{'titleText': 'Hero Banner Title'}"></hero-banner>3. Custom attributes
<hero-banner title-text="Hero Banner Title"></hero-banner>You'll need to define your custom attributes up front when using define(), e.g:
define('hero-banner', () => HeroBanner, ['title-text']);These will then be merged into your components props in camelCase, so title-text will become titleText.
Nested HTML
You can also provide nested HTML to your components children property. For example:
<hero-banner>
<h2>Banner Title</h2>
</hero-banner>This will correctly convert the <h2> into virtual DOM nodes for use in your component, e.g:
/*[...]*/
function HeroBanner({ children }) {
return <section>{children}</section>;
}ES5 Support
To support ES5 or older browsers, like IE11, you'll need to install the official Web Component Custom Element polyfill. Once installed, you'll need to import the following at the very top of your entry files:
import '@webcomponents/custom-elements';
import '@webcomponents/custom-elements/src/native-shim';Acknowledgement
This function takes heavy inspiration from the excellent preact-custom-element. That library served as a starting point for this package, and all of the Preact guys deserve a massive dose of gratitude. I had slightly different needs, so decided to build this as part solution, part learning excersize.