Skip to content

Web Components ​

AkashJS components can be compiled to native Custom Elements, making them usable in plain HTML, React, Vue, Svelte, or any other framework.

defineCustomElement() ​

Register an AkashJS component as a custom element with a single call:

ts
import { defineCustomElement } from '@akashjs/runtime';
import Counter from './Counter.akash';

defineCustomElement('my-counter', Counter, {
  props: ['initial', 'step'],
  shadow: true,
  styles: ':host { display: block; }',
});

The component is now available as <my-counter> in any HTML page.

Options ​

OptionTypeDefaultDescription
propsstring[][]Attribute names to observe and pass as props
shadowbooleantrueUse Shadow DOM for style encapsulation
stylesstring--CSS to inject into the shadow root
extendsstring--Extend a built-in HTML element (e.g. 'button')

Props as Attributes ​

Properties listed in the props array are observed as HTML attributes. When an attribute changes, the component re-renders with the new value:

html
<my-counter initial="5" step="2"></my-counter>

Attribute values are automatically parsed: "5" becomes the number 5, "true" becomes the boolean true, and JSON strings are parsed into objects. Plain strings are kept as-is.

You can also set props programmatically:

ts
const el = document.querySelector('my-counter');
el.setProps({ initial: 10, step: 3 });

Shadow DOM ​

By default, custom elements use Shadow DOM to encapsulate styles. Set shadow: false to render directly into the element (light DOM):

ts
defineCustomElement('my-widget', Widget, {
  props: ['title'],
  shadow: false,  // styles from the page will apply
});

Styles Injection ​

When using Shadow DOM, inject component styles via the styles option:

ts
defineCustomElement('my-card', Card, {
  shadow: true,
  styles: `
    :host {
      display: block;
      border: 1px solid #e0e0e0;
      border-radius: 8px;
      padding: 1rem;
    }
    ::slotted(h2) {
      margin-top: 0;
    }
  `,
});

toCustomElement() ​

If you want the Custom Element class without auto-registering it, use toCustomElement():

ts
import { toCustomElement } from '@akashjs/runtime';

const MyCounterElement = toCustomElement(Counter, {
  props: ['initial'],
  shadow: true,
});

// Register manually whenever you want
customElements.define('my-counter', MyCounterElement);

This is useful for testing, lazy registration, or conditional registration.

Usage in Plain HTML ​

After registering the custom element (e.g., in a <script> tag or a bundled JS file), use it like any HTML element:

html
<!DOCTYPE html>
<html>
<head>
  <script type="module" src="/components.js"></script>
</head>
<body>
  <my-counter initial="0"></my-counter>
  <my-card>
    <h2>Hello</h2>
    <p>Content goes here.</p>
  </my-card>
</body>
</html>

Usage in Other Frameworks ​

React ​

jsx
function App() {
  return <my-counter initial={5} />;
}

Vue ​

vue
<template>
  <my-counter :initial="5" />
</template>

Svelte ​

svelte
<my-counter initial={5} />

Custom elements are framework-agnostic by design. Any framework that renders HTML can use them.

Extending Built-in Elements ​

Use the extends option to create customized built-in elements:

ts
defineCustomElement('fancy-button', FancyButton, {
  props: ['variant'],
  extends: 'button',
});
html
<button is="fancy-button" variant="primary">Click me</button>

Note: customized built-in elements are not supported in WebKit/Safari.

Released under the MIT License.