Callee is excited you’re going to build some components!

Heartml is Postmodern HTML. 🍭
Web components that just can't get enough of that sweet declarative markup. 🥰

Heartml is a versatile new web component format, centered around present-day open standards and running in the direction of future ones.

You can define Heartml components entirely in JavaScript, in declarative Single-File Component HTML module files, or simply embedded directly in any HTML page. Build steps? Completely optional!

Write split components (all markup is rendered server-side, then upgraded with client-side behavior), hybrid components (markup from server, but shipping with a template so new components can be initialized on the client), or client-side only components—you decide!

Forget everything you know about web components…and fall in love with them all over again.

Features! So Many Features!

Every Component Everywhere All at Once

Choose Your Flavor

Extensible by Design

How to Install

From a CDN:

  <script src=""></script>

From a package:

npm i heartml
import { HeartElement } from "heartml"

Heartml in Action

Declarative Custom Elements (DCEs)

Heartml lets you define custom elements declaratively directly in your HTML using heart-ml tags. This is particularly useful for co-locating components with specific use cases right in the contexts where they’ll be used.

Heartml Module Files (SFCs)

Moving a step up from DCEs, you can author .heartml files—a Single-File Component format which starts with pure HTML. You can import and bundle .heartml files via esbuild or alternatively use the <heart-module> custom element to load them up in any “buildless” environment.

Write a Plugin

Virtually all Heartml functionality is provided by plugins. Every static property on your class is checked to determine if it should activate a plugin. So writing your own is simply a matter of adding some code to the Hearml.plugins object, and using that key as a static property on your component class.

This pattern doubles as a configuration mechanism, and even works as pure JSON within declarative custom element attributes! (Any kebob-case plugin attribute gets converted to camelCase automatically.)

Works Great with Design Systems…Like Shoelace!

If it’s another custom element, you’re golden. Mix ‘n’ match however you like. Just keep an eye on your total bundle size. (But if you employ Islands Architecture and use tools like <is-land>…might not even matter!)