Skip to content

Turn your JSX elements into native DOM elements.

Notifications You must be signed in to change notification settings

turtlemay/jsx-dom

Repository files navigation

@turtlemay/jsx-dom

This minimal, zero-dependency JSX factory allows you to use React-like design patterns with web components and other native DOM elements. Most JSX patterns and special attributes are supported.

npm (scoped)

Example

import * as React from '@turtlemay/jsx-dom'

// Define a custom element type.
class MyCustomElement extends HTMLElement {
  connectedCallback() {
    this.innerHTML = ''
    this.appendChild(<p>hello {MyCustomElement.name}</p>)
  }
}

// Register our custom element.
customElements.define(`x-${MyCustomElement.name.toLowerCase()}`, MyCustomElement)

// Use the custom element type like a React component.
document.body.appendChild(
  <MyCustomElement
    // Use the ref callback to save your element reference.
    ref={v => this._myElemRef = v}

    // Props matching a native property name will be assigned to that property.
    onclick={e => {}}
    // Camel cased event callbacks are also assigned via the corresponding native property.
    onMouseDown={e => {}}

    // Style objects are also supported.
    style={{ border: '1px solid red' }}

    // Anything else becomes a native attribute.
    my-string-attrib="foo"
    my-number-attrib={0}
    my-boolean-attrib={true}
    // Objects become json-stringified.
    my-object-attrib={{ foo: "bar" }} />
)

Installation

npm install @turtlemay/jsx-dom

Usage

Simply import the module into your JSX files using the React namespace:

import * as React from '@turtlemay/jsx-dom'

And write some JSX:

const attribs = {
  foo: 'foo',
  bar: 'bar',
}
const div = <div {...attribs} baz="baz" qux="qux" />

JSX elements become native DOM elements:

console.assert(
  <div /> instanceof HTMLDivElement
)

And fragments become document fragments:

console.assert(
  <></> instanceof DocumentFragment
)

Optional Configuration

With TypeScript you can use a namespace other than React by setting your tsconfig.json:

{
  "jsx": "react",
  "reactNamespace": "JSXFactory"
}
import * as JSXFactory from '@turtlemay/jsx-dom'

const div = <div />

Tips

Use a decorator for easy component registration:

// Decorator with optional tag name to define custom elements.
function registerComponent(tagName) {
  return type => {
    if (!tagName) tagName = 'x-' + type.name.toLowerCase()
    if (customElements.get(tagName)) return
    customElements.define(tagName, type)
  }
}

// Decorate your components.
@registerComponent()
class MyComponent extends HTMLElement {}

For passing non-serializable props, use an initializer:

@registerComponent()
class MyComponent extends HTMLElement {
  init(myArg) {
    // Use your arguments to perform initialization.
    return this
  }
}

document.body.appendChild(
  MyComponent.prototype.init.call(
    <MyComponent my-serializable-prop="" />,
    { myNonSerializableProp: Symbol() }
  )
)

About

Turn your JSX elements into native DOM elements.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published