Skip to content

Instantly share code, notes, and snippets.

@domenic
Last active November 11, 2020 15:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save domenic/e3e1e034e119826f394480cd9f15e211 to your computer and use it in GitHub Desktop.
Save domenic/e3e1e034e119826f394480cd9f15e211 to your computer and use it in GitHub Desktop.
Web components reflection

Web components reflection

What is a subset of HTML's reflection rules which we should make easy for web components?

Summary of HTML

HTML's reflection algorithms include:

  • URL strings
  • Enumeration strings ("limited to only known values")
    • Missing value default
    • Invalid value default
    • Note: case-insensitive
  • Other strings
  • Booleans
  • A bunch of numbers:
    • long
    • long limited to only non-negative numbers
    • unsigned long
    • unsigned long limited to only non-negative numbers greater than zero
    • unsigned long limited to only non-negative numbers greater than zero with fallback
    • double/unrestricted double
    • double/unrestricted double limited to numbers greater than zero
  • DOMTokenList
  • HTMLElement

Proposed custom elements capabilities

  • URL strings
  • Enumeration strings:
    • Case-insensitive to match the platform
    • Make missing and invalid value default always the same
    • Maybe make missing and invalid value default always ""?
  • Other strings
  • Booleans
  • Numbers, parametrized:
    • Lower bound (+ upper bound?)
    • Integral or floating point
    • Integer default upper bound is 2147483647 to match the platform.
    • Setting out-of-bound values causes an exception
    • Getting when the attribute has out of bound values returns the lower bound? Returns null? Returns a configurable fallback?

This omits:

  • No DOMTokenList for now since it's not constructible
  • No HTMLElement since id-based references kind of suck
  • Various existing number behavior such as wrapping at 2147483647 or clamping to >=0.

Proposed API shape:

customElements.addReflectingProperties(MyCustomElement, {
    href: 'url',
    selected: 'boolean',
    label: 'string',

    preload: {
      type: 'enum',
      values: ['none', 'metadata', 'auto'],
      default: 'auto'
    },
    // Alternative to preload syntax
    preload2: {
        type: 'enum',
        values: ['none', 'metadata'] // implicit '' value is interpreted
                                     // by the component as auto behavior
        // default is always ''
    },

    colSpan: {
        type: 'int',
        lowerBound: 1
    },
    width: {
        type: 'float',
        lowerBound: 0
    },

    // Alternative to colSpan/width syntax
    colSpan2: {
        type: 'number',
        integral: true,
        lowerBound: 1
    },
    width2: {
        type: 'number',
        lowerBound: 0
    }
});

With decorators

const { url, boolean, string, enum, enum2, enum3, int, float } = customElements.decorators;

class MyCustomElement extends HTMLElement {
    @url href;
    @boolean selected;
    @string label;

    @enum({ values: ['none', 'metadata', 'auto'], default: 'auto' }) preload;

    // Alternative: assume the first is the default
    @enum2('auto', 'metadata', 'none') preload2;

    // Alternative: implicit '' default
    @enum3('metadata', 'none') preload3;

    @int({ lowerBound: 1 }) colSpan;

    @float({ lowerBound: 0 }) width;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment