miqro · @miqro/core · @miqro/parser · @miqro/query · @miqro/jsx · @miqro/jsx-dom · @miqro/jsx-node · @miqro/request · @miqro/runner · @miqro/test · @miqro/test-http
browser runtime for @miqro/jsx. define Web Components.
wrap a JSX component as a custom element.
import JSX, { useState, Props } from "@miqro/jsx";
import { define } from "@miqro/jsx-dom";
function Counter(props: Props) {
const [n, setN] = useState(Number(props.initial) || 0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}
define("my-counter", Counter, {
shadowInit: false
});
use in HTML:
<my-counter initial="5"></my-counter>
<script src="/js/counter.js"></script>
props from attributes are always strings. parse manually for other types.
an attribute listed here re-invokes the component with the new props when it changes. an attribute that is not listed does not.
function Label(props: Props) {
return <p>{props.initial}</p>;
}
define("my-label", Label, {
observedAttributes: ["initial"],
shadowInit: false
});
the value has to be read from props to follow the attribute. useState keeps the value it was
first given, so the Counter above stays on its first number however initial changes later:
the re-render happens and the component does see the new prop, it just does not use it.
define("my-counter", Counter, { shadowInit: false }); // no shadow DOM
define("my-counter", Counter, { shadowInit: { mode: "open" } }); // open shadow root
define("my-counter", Counter, { shadowInit: { mode: "closed" } }); // closed shadow root
// default when omitted: closed shadow root
leaving shadowInit out is not the same as false. the element gets a closed shadow
root, so page level CSS does not reach the rendered content and element.shadowRoot reads
null from the outside. pass shadowInit: false for a component that should render into the
light DOM.
this is the container's own shadow root, separate from MyComponent.shadowInit, the per
component option in @miqro/jsx, which defaults to false.
$element$ prop gives access to the raw HTMLElement:
function MyComponent(props: Props) {
const el = props["$element$"]; // HTMLElement
}
child nodes passed as children prop:
<my-card>
<p>this becomes children</p>
</my-card>
they are moved out of the custom element and read once, when it first connects, so nodes added to the light DOM afterwards are not picked up.
mount any JSX component into a DOM element without defining a custom element.
import { createDOMContainer } from "@miqro/jsx-dom";
import { createElement } from "@miqro/jsx";
const root = document.getElementById("root");
if (!root) throw new Error("no #root");
const container = createDOMContainer(root, {
shadowInit: false,
runtimeOptions: {
disableEffects: false,
disableEvents: false
}
});
container.render(createElement(MyComponent, { title: "hello" }));
container.disconnect(); // cleanup
shadowInit works the same as in define, including the default: omitting it renders into a
closed shadow root on root rather than into root itself.