developit / htm

Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.
Apache License 2.0
8.67k stars 170 forks source link

Allow users to register element names #167

Open dfabulich opened 4 years ago

dfabulich commented 4 years ago

https://github.com/esxjs/esx looks a lot like HTM, but instead of handling components as <${Foo}>, you have to (get to?) pre-register component names, like this: esx.register({Foo})

Then you can use custom components like this:

esx`<Foo bar=baz>Blah</Foo>`

It would be cool if this were an option for HTM as well.

yhatt commented 3 years ago

You can bind a function works like a proxy to render pre-registered components.

import { h, render } from 'https://unpkg.com/preact?module';
import htm from 'https://unpkg.com/htm?module';

const App = ({ children }) => ['Hello, ', children, '!']

// Imitation of createEsx()
const createEsx = (components) =>
  htm.bind((type, ...rest) => h(components[type] || type, ...rest))

const esx = createEsx({ App })
render(esx`<App>world</App>`, document.getElementById('app'))
developit commented 3 years ago

@yhatt exactly! There's also a way to do this for everything rendered by Preact, including elements created via h() and JSX:

import { options, h, render } from 'https://unpkg.com/preact?module';
import htm from 'https://unpkg.com/htm?module';
const html = htm.bind(h);

// component registry
const components = {};
components.App = ({ children }) => ['Hello, ', children, '!'];

// inject component registry into Preact itself:
let old = options.vnode;
options.vnode = vnode => {
  if (vnode.type in components) vnode.type = components[vnode.type];
  if (old) old(vnode);
};

// now it's global!
render(html`<App>world</App>`, document.body);
// or:
render(h('App', {}, 'world'), document.body);