npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ce-decorators

v2.6.1

Published

Custom Element decorators for typescript

Downloads

61

Readme

CE-DECORATORS

ce-decorators is a typescript library for custom element development. It is powered by lit-html for effective DOM updates. The decorator API is similar to stenciljs but without the need of a special compiler, just the ts-compiler is needed.

The decorators will take care of style registering if the ShadyCSS scoping shim is needed, attribute-property reflection with type transformation from attribute to property and vice versa. All in just 14kb (26kb with lit-html bundled).

Custom elements

Custom elements are user defined HTML elements, which offer customized functionalities and styling. When used inide an HTML template it looks like this:

<custom-button primary>
 Click this Button
</custom-button>

In this example custom-button is the tag-name of the element, primary is a specific attribute and Click this button is a slot element passed in the element for further processing.

For detailed information about custom elements see

https://developers.google.com/web/fundamentals/web-components/

Compatibility

The library is compatible with IE11 (needs babel transpile), Chrome, FF, Edge, Safari and the mobile Safari and Chrome Browser.

For IE11 you need: @webcomponents/webcomponentsjs polyfills and Polyfills for Symbol, Map, WeakMap and Promises For Edge you need: @webcomponents/webcomponentsjs in FF, Safari and Chrome everything should just work.

If you compile all down to ES5 you need for all Brwosers the custom-elements-es5-adapter.js.

Benefits

  • No boilerplate code
  • Code completion since all properties are named and have types

Installation

npm install ce-decorators important! you need the following compiler settings in your tsconfig.json

"emitDecoratorMetadata": true,
"experimentalDecorators": true

Usage

import { Component, Prop ..} from 'ce-decorators'

babel dependencies (for ES5):

"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-typescript": "^7.0.0", (optional only when using typescript)

babel config:

plugins: [
  ["@babel/plugin-proposal-decorators", { legacy: true/false}],
  ["@babel/plugin-proposal-class-properties", { "loose" : true }]
]

Both decorator specification (Stage-0 and Stage-2 are supported).

If decorators are used with babel the data type for the Prop decorator has to be specified, otherwise attribute reflection won't work.

Sample

import { Component, CustomElement, Event, EventEmitter, Interceptor, Prop, State, Watch, html } from 'ce-decorators';

@Component({
  tag: 'my-custom-element',
  style: `
    :host {
        background-color : #f0f;
    }
    `,
})
export class MyCustomElement extends CustomElement {

  @Prop()
  propertyOne: string = 'default value'; // register a property propertyOne with a reflection to attribute property-one

  @Event()
  change: EventEmitter<string>; // will trigger a custom event with name "change" (name can be overriden by decorator argument)

  @State()
  private myState: boolean = false; // only visible to the instance, will not reflect but trigger a re-render

  @Watch('propertyOne') // watches for changes in propertyOne (changes to properties within this method will not be reflected, please use intercept for that case)
  propertyOneChanged(oldValue: string, newValue: string) {
    console.log('propertyOne Changed');
  }

  @Interceptor('propertyOne') // watches for changes of propertyOne and change the value, the changed value will be reflected and written
  propertyOneInterceptor(oldValue: string, newValue: string) {
    return newValue + 'test';
  }

  render() {
    return html`<div>${this.propertyOne}</div>`;
  }

  componentConnected() {
      console.log('element attached to the DOM');
  }

  componentDisconnected() {
      console.log('element dettached from the DOM');
  }

  componentWillRender() {
      console.log('render will be called')
  }

  componentDidRender() {
      console.log('render was called')
  }
}

Lifecycle

Construction/rendering

  1. constructor call
  2. resolve promise returned by waitForConstruction() on custom element (awaitable)
  3. <append to dom>
  4. componentConnected()
  5. <if a property changed or first connect deferred in microtask (in asnyc task if you use LazyCustomElement)>
  6. componentWillRender(): property changes within this function will be taken into account in the rendering step
  7. render()
  8. componentDidRender(): can be used for post-processing runs in the same asnyctask/microtask as render
  9. resolve promise returned by waitForRender() on custom element (awaitable)
  10. <if property or attribute changed (deferred in microtask)>
  11. render() deferred in microtask or in asnyc task if you use LazyCustomElement
  12. <remove/detach from dom>
  13. componentDisconnected()

In code

const element = new MyCustomElement();
await element.waitForForConstruction();

element.propertyOne = 'test'; // will be reflected as property-one attribute
document.querySelector('body').appenChild(element);
    // element.componentConnected() called
await element.waitForRender();
    // element.componentWillRender() called
    // element.render() called
    // element.componentFirstRender() called *only called on first render*
    // element.componentDidRender() called
document.querySelector('body').removeChild(element);
    // element.componentDisconnected() called

Because render calls are deferred into a microtask or async task, setting multiple attributes/properties consecutively will result in just one render call.

Property updates

  1. set property myProperty
  2. run interceptors
  3. if reflectToAttribute is set for myProperty (or undefined, which is the default case), the property will be reflected as attribute my-property
  4. notify watchers
  5. deffer render() to microtask (so if multiple attributes/properties are set in the same task, render is only called once)

LazyCustomElement

LazyCustomElement is an alternative to the default CustomElement which renders in an asnyc task (setTimeout) instead of a microtask .

Usage

Use with Angular

For angular CUSTOM_ELEMENTS_SCHEMA needs to be activated. Now custom elements can be used like angular components.

in the component:

import './my-custom-element'

in the template:

<my-custom-element [propertyOne]="this.propertyOne" attribute-one="this.attributeOne" (change)="$evt => handleEvent($evt)">
</my-custom-element>

Use with react

In react you need to pass everything as attributes

import 'my-custom-element';

render(<my-custom-element property-one="{propertyOne}"></my-custom-element>)