Last active
November 18, 2025 16:18
-
-
Save kenwebb/6d8fbf279088cc552494f12b87d7cbe8 to your computer and use it in GitHub Desktop.
preact - HTM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Tue Nov 18 2025 11:18:05 GMT-0500 (Eastern Standard Time)--> | |
| <XholonWorkbook> | |
| <Notes><![CDATA[ | |
| Xholon | |
| ------ | |
| Title: preact - HTM | |
| Description: | |
| Url: http://www.primordion.com/Xholon/gwt/ | |
| InternalName: 6d8fbf279088cc552494f12b87d7cbe8 | |
| Keywords: | |
| My Notes | |
| -------- | |
| 2025 Nov 16 | |
| In this workbook, I will construct a GUI using HTM, that will be useful with a Xholon app. | |
| ### References | |
| (1) https://preactjs.com/guide/v10/no-build-workflows#htm | |
| Whilst JSX is generally the most popular way to write Preact applications, | |
| it requires a build step to convert the non-standard syntax into something browsers and other runtimes can understand natively. | |
| Writing h/createElement calls by hand can be a bit tedious though with less than ideal ergonomics, | |
| so we instead recommend a JSX-like alternative called HTM. | |
| Instead of requiring a build step (though it can use one, see `babel-plugin-htm`), | |
| HTM uses Tagged Templates syntax, a feature of JavaScript that's been around since 2015 and is supported in all modern browsers. | |
| This is an increasingly popular way to write Preact apps and is likely the most popular for those choosing to forgo a build step. | |
| HTM supports all standard Preact features, including Components, Hooks, Signals, etc., | |
| the only difference being the syntax used to write the "JSX" return value. | |
| (2) https://github.com/developit/htm | |
| HTM (Hyperscript Tagged Markup) | |
| htm is JSX-like syntax in plain JavaScript - no transpiler necessary. | |
| Develop with React/Preact directly in the browser, then compile htm away for production. | |
| It uses standard JavaScript Tagged Templates and works in all modern browsers. | |
| Syntax: like JSX but also lit | |
| The syntax you write when using HTM is as close as possible to JSX: | |
| Spread props: <div ...${props}> instead of <div {...props}> | |
| Self-closing tags: <div /> | |
| Components: <${Foo}> instead of <Foo> (where Foo is a component reference) | |
| Boolean attributes: <div draggable /> | |
| Improvements over JSX | |
| htm actually takes the JSX-style syntax a couple steps further! | |
| Here's some ergonomic features you get for free that aren't present in JSX: | |
| No transpiler necessary | |
| HTML's optional quotes: <div class=foo> | |
| Component end-tags: <${Footer}>footer content<//> | |
| Syntax highlighting and language support via the lit-html VSCode extension and vim-jsx-pretty plugin. | |
| Multiple root element (fragments): <div /><div /> | |
| Support for HTML-style comments: <div><!-- comment --></div> | |
| Installation | |
| htm is published to npm, and accessible via the unpkg.com CDN: | |
| via npm: | |
| npm i htm | |
| hotlinking from unpkg: (no build tool needed!) | |
| import htm from 'https://unpkg.com/htm?module' | |
| const html = htm.bind(React.createElement); | |
| // just want htm + preact in a single file? there's a highly-optimized version of that: | |
| import { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js' | |
| Usage | |
| If you're using Preact or React, we've included off-the-shelf bindings to make your life easier. They also have the added benefit of sharing a template cache across all modules. | |
| import { render } from 'preact'; | |
| import { html } from 'htm/preact'; | |
| render(html`<a href="/">Hello!</a>`, document.body); | |
| Similarly, for React: | |
| import ReactDOM from 'react-dom'; | |
| import { html } from 'htm/react'; | |
| ReactDOM.render(html`<a href="/">Hello!</a>`, document.body); | |
| and more ... | |
| (3) https://www.npmjs.com/package/htm | |
| ### Code from ref[1] | |
| import { render } from 'preact'; | |
| import { useState } from 'preact/hooks'; | |
| import { html } from 'htm/preact'; | |
| function Counter() { | |
| const [count, setCount] = useState(0); | |
| return html` | |
| <div class="counter-container"> | |
| <button onClick=${() => setCount(count + 1)}>Increment</button> | |
| <input readonly value=${count} /> | |
| <button onClick=${() => setCount(count - 1)}>Decrement</button> | |
| </div> | |
| `; | |
| } | |
| render(html`<${Counter} />`, document.getElementById('app')); | |
| () | |
| ]]></Notes> | |
| <_-.XholonClass> | |
| <!-- domain objects --> | |
| <PhysicalSystem/> | |
| <Block/> | |
| <Brick/> | |
| <!-- quantities --> | |
| <Height superClass="Quantity"/> | |
| </_-.XholonClass> | |
| <xholonClassDetails> | |
| <Block> | |
| <port name="height" connector="Height"/> | |
| </Block> | |
| </xholonClassDetails> | |
| <PhysicalSystem> | |
| <Block> | |
| <Height>0.1 m</Height> | |
| </Block> | |
| <Brick multiplicity="2"/> | |
| </PhysicalSystem> | |
| <Blockbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| var a = 123; | |
| var b = 456; | |
| var c = a * b; | |
| if (console) { | |
| console.log(c); | |
| } | |
| //# sourceURL=Blockbehavior.js | |
| ]]></Blockbehavior> | |
| <Heightbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| var myHeight, testing; | |
| var beh = { | |
| postConfigure: function() { | |
| testing = Math.floor(Math.random() * 10); | |
| myHeight = this.cnode.parent(); | |
| }, | |
| act: function() { | |
| myHeight.println(this.toString()); | |
| }, | |
| toString: function() { | |
| return "testing:" + testing; | |
| } | |
| } | |
| //# sourceURL=Heightbehavior.js | |
| ]]></Heightbehavior> | |
| <Brickbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| $wnd.xh.Brickbehavior = function Brickbehavior() {} | |
| $wnd.xh.Brickbehavior.prototype.postConfigure = function() { | |
| this.brick = this.cnode.parent(); | |
| this.iam = " red brick"; | |
| }; | |
| $wnd.xh.Brickbehavior.prototype.act = function() { | |
| this.brick.println("I am a" + this.iam); | |
| }; | |
| //# sourceURL=Brickbehavior.js | |
| ]]></Brickbehavior> | |
| <Brickbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
| console.log("I'm another brick behavior"); | |
| ]]></Brickbehavior> | |
| <SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
| <svg width="100" height="50" xmlns="http://www.w3.org/2000/svg"> | |
| <g> | |
| <title>Block</title> | |
| <rect id="PhysicalSystem/Block" fill="#98FB98" height="50" width="50" x="25" y="0"/> | |
| <g> | |
| <title>Height</title> | |
| <rect id="PhysicalSystem/Block/Height" fill="#6AB06A" height="50" width="10" x="80" y="0"/> | |
| </g> | |
| </g> | |
| </svg> | |
| ]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
| </XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment