Web components have a lot of similarities with Angular Components. They can have input attributes.

If you have a custom element with a custom input attribute bookname In Angular you write

<app-myelement [bookname]="'My Book'"></app-myelement>

To pass in values, and without Angular

<app-myelement bookname="My Book"></app-myelement>

But while vanilla Elements only support string attributes, Angular can pass in any type. If an Angular Component has a field

book = {title: "Adam", year: 1900};

you can pass it as an input

<app-angular-element [bookdata]="book"></app-angular-element>

What is surprising though is that the exact same thing works when you are using Angular with a vanilla Element that accepts a non-string attribute.

<app-vanilla-element [bookdata]="book"></app-vanilla-element>

And you write it in the exact same way.

This is possible because inputs can be passed into Custom Elements in two different ways: via attributes which only accept strings, and via setters which can accept any type.

If you correctly define your Custom Element to support both methods, you'll have great reusability both with and without a framework.

class BookElement extends HTMLElement {

    constructor() {
        this._bookdata = null;

    static get observedAttributes() {
        return [

    attributeChangedCallback(name, old, newValue) {
        if (name == "bookdata") {
            this.bookdata = newValue;

    set bookdata(value) {
        this._bookdata = value;


In this element, the bookdata input can be set via attribute, meaning that this._bookdata will be a string, and via setter, making this._bookdata any type.

Using HTML attributes relies on observedAttributes and attributeChangedCallback, while using Angular bypasses those two methods and uses the setter.