miqro · @miqro/core · @miqro/parser · @miqro/query · @miqro/jsx · @miqro/jsx-dom · @miqro/jsx-node · @miqro/request · @miqro/runner · @miqro/test · @miqro/test-http

@miqro/jsx-dom

browser runtime for @miqro/jsx. define Web Components.

define

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.

observedAttributes

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.

shadowInit

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$

$element$ prop gives access to the raw HTMLElement:

function MyComponent(props: Props) {
  const el = props["$element$"]; // HTMLElement
}

children

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.

createDOMContainer

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.