Elements are the reusable building blocks of your Enhance application. They are pure functions authored as single-file components. They’re also server-side rendered out of the box, offering incredible performance and a seamless path for progressive enhancement.

Elements live in the app/elements/ folder in the Enhance starter project.


The file name of your element will be the tag name you author with. Meaning app/elements/my-message.mjs will be authored as <my-message></my-message> in your HTML page. Enhance elements are HTML custom elements, so they require two or more words separated by a dash.

app/elements/my-message → <my-message></my-message>
app/elements/my-link → <my-link></my-link>

When a project grows to include more elements than can comfortably fit in a single folder, they can be divided into sub-directories inside app/elements/. The folder name becomes part of the custom element tag name:

app/elements/blog/comment → <blog-comment></blog-comment>
app/elements/blog/comment-form → <blog-comment-form></blog-comment-form>


Elements are pure functions — meaning: given the same input, they return the same output every single time. Your element function will be passed an arguments object containing an html render function that is used to expand nested custom elements.

export default function MyHeader({ html }) {
  return html`
      <my-link href="/about"></my-link>


Your element function is also passed a state object in the arguments object. This state object is comprised of attrs: an object of key value pairs representing the attributes added to your custom element tag, and store: an object containing application state.

In this example you create an element with a default description then use an API route to populate the store description data. This allows you to supply a different description per page.

export default function MyHeader({ html, state }) {
  const { attrs, store } = state
  const { heading = 'Default' } = attrs
  const { description = 'A default description' } = store

  return html`

Your index API route could return a JSON payload to update the description in the <my-header> element on the index page.

export async function get() {
  return {
    json: {
      description: 'Welcome to the index page'

Community Resources


Visit Enhance on GitHub.


Join our Discord server to chat about development and get help from the community.


Follow Enhance in the Fediverse. We're huge fans of the IndieWeb!