• Stars
    star
    196
  • Rank 198,553 (Top 4 %)
  • Language
    JavaScript
  • Created over 7 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

VirtualDOM abstraction layer - give yourself better integration and full control over the DOM with any virtual DOM library that uses a Hyperscript-like API such as React and Preact.

Val

Travis

Better VDOM / DOM integration

The goal of this wrapper is to provide a consistent interface across all virtual DOM solutions that provide a hyperscript-style virtual DOM function, and also provide a default interface for creating real DOM. This includes, but is not limited to:

  • React
  • Preact
  • Virtual DOM
  • Hyperscript (any implementation)
  • Real DOM
  • ...
npm install @skatejs/val

Rationale

The problems these different implemenations face is that the only common thing is the function that you invoke and the arguments that it accepts, at a top level. However, they all behave differently with the arguments you give them.

For example, React will only set props on DOM elements that are in its whitelist. Preact will set props on DOM elements if they are in element. There's problems with each of these.

The problem with React is that you can't pass complex data structures to DOM elements that have properties that aren't in their whitelist, which every web component would be subject to.

With Preact, it's mostly good. However, the assumption is that your custom element definition is defined prior to Preact creating the DOM element in its virtual DOM implementation. This will fail if your custom element definitions are loaded asynchronously, which is not uncommon when wanting to defer the loading of non-critical resources.

Theres other issues such as React not working at all with custom events.

Solution

The best solution I've come across so far is to create a wrapper that works for any of these. The wrapper enables several things:

  • Ability to pass a custom element constructor as the node name (first argument).
  • Explicit control over which DOM attributes to set (via attrs: {} in the second argument.)
  • Explicit control over which DOM events are bound (via events: {} in the second argument).
  • Explicit control over which DOM props are set (via props: {}) in the second argument).
  • Everything else is just passed through and subject to the standard behaviour of whatever library you're using.
  • The ref you pass will be wrapped so that val can do its thing.

Requirements

This assumes that whatever library you're wrapping has support for a ref callback as a common way for us to get access to the raw DOM element that we need to use underneath the hood.

Usage

The usage is simple. You import the wrapper and invoke it with the only argument being the virtual DOM function that you want it to wrap.

React:

import { createElement } from "react";
import val from "@skatejs/val";

export default val(createElement);

Preact:

import { h } from "preact";
import val from "@skatejs/val";

export default val(h);

In your components, you'd then import your wrapped function instead of the one from the library.

/** @jsx h */

import h from "your-wrapper";
import { PureComponent } from "react";
import { render } from "react-dom";

class WebComponent extends HTMLElement {}
class ReactComponent extends PureComponent {
  render() {
    return <WebComponent />;
  }
}

render(<ReactComponent />, document.getElementById("root"));

Real DOM

Val ships with a default adapter that generates real DOM nodes. To do this, simply import the h function:

/** @jsx h*/
import { h } from "@skatejs/val";

// <div>test</div>
console.log(<div>test</div>.outerHTML);

Everything works as advertised, so you can still pass custom elements, attributes and events as you normally would and things just work.

Being able to do this is immensely useful for testing real DOM and web components. Apply liberally!

DOM attributes

Attributes are specified using the attrs object.

import h from "your-wrapper";

h("my-element", {
  attrs: {
    "my-attribute": "some value"
  }
});

DOM events and custom events

Events are bound using the events object. This works for any events, including custom events.

import h from "your-wrapper";

h("my-element", {
  events: {
    click() {},
    customevent() {}
  }
});

DOM properties

Properties are categorised as anything that is not attrs or events.

h("my-element", {
  props: {
    someProp: true
  }
});

Standard framework props

Anything else is just passed through to your framework.

// @jsx h

import val from "@skatejs/val";
import { createElement } from "react";

const h = val(createElement);

// The onClick prop gets passed through to React.
<button onClick={() => {}} />;

Custom element constructors

You can also use your web component constructor instead of the name that was passed to customElements.define().

// So we have the reference to pass to h().
class CustomElement extends HTMLElement {}

// It must be defined first.
customElements.define("custom-element", CustomElement);

// Now we can use it.
h(CustomElement);

More Repositories

1

skatejs

Effortless custom elements powered by modern view libraries.
JavaScript
3,281
star
2

ssr

Your one-stop shop for testing and rendering web components on the server.
JavaScript
137
star
3

dom-diff

Library for efficiently diffing and patching virtual and real DOM fragments.
JavaScript
98
star
4

bore

An Enzyme-like testing utility built for the DOM and Web Components.
JavaScript
40
star
5

web-components

[DEPRECATED] - The frictionless way to use the webcomponents/webcomponentsjs polyfills.
JavaScript
17
star
6

renderer-preact

SkateJS renderer for Preact.
JavaScript
15
star
7

named-slots

[DEPRECATED] - A pseudo-polyfill for the Shadow DOM Named Slot API.
JavaScript
15
star
8

wc-parser

Parser declarative custom elements and imports into JavaScript definitions.
JavaScript
11
star
9

kickflip

[DEPRECATED] - Functional web components based on the W3C web component specifications.
JavaScript
11
star
10

generator-skatejs

[UNMAINTAINED] Yeoman Generator for Skatejs Components
JavaScript
11
star
11

renderer-react

React renderer for SkateJS.
JavaScript
9
star
12

template-html

[DEPRECATED] - ShadowDOM-like HTML templating.
JavaScript
6
star
13

renderer-lit-html

Lit HTML renderer for SkateJS.
JavaScript
5
star
14

sk-router

A web component router that's compatible with code-splitting out of the box.
JavaScript
5
star
15

skatejs.github.io

[DEPRECATED] - SkateJS library, components and extensions.
JavaScript
5
star
16

shade

[DEPRECATED] - Simple ShadowDOM style templating.
JavaScript
3
star
17

build

[DEPRECATED] - Common build tasks for all Skate projects.
JavaScript
3
star
18

types

[DEPRECATED] - Alternate binding types (e.g. attribute / classname) for SkateJS.
JavaScript
3
star
19

project

Repository containing everything from roadmap to maintainer meetings.
2
star
20

vert

Official set of web components written with Skate.
JavaScript
1
star