Documentation

Quick Start

The fastest way to get started is with our CLI scaffold:

npx create-html-elements

Choose between bare HTML & CSS or HTML with Tailwind (includes Prettier).

Why HTML Elements?

Keep your HTML DRY without framework overhead. Compose reusable components at build time with zero runtime JavaScript.

  • No virtual DOM, no hydration, no runtime JS
  • Works with any CSS framework (Tailwind, plain CSS, etc.)
  • Fast dev experience with hot reloading
  • Production builds are pure static HTML

Manual Installation

Or install the plugin manually:

npm install -D vite-plugin-html-elements

Configuration

Add the plugin to your Vite config:

// vite.config.js
import { defineConfig } from 'vite';
import { htmlElements } from 'vite-plugin-html-elements';

export default defineConfig({
  plugins: [htmlElements()]
});

For TypeScript projects:

// vite.config.ts
import { defineConfig } from 'vite';
import { htmlElements } from 'vite-plugin-html-elements';

export default defineConfig({
  plugins: [htmlElements()]
});

Basic Usage

Create reusable HTML elements in an elements/ directory:

project/
├── public/
│   ├── favicon.png
│   └── logo.webp
├── src/
│   ├── elements/
│   │   ├── head.html
│   │   ├── header.html
│   │   └── footer.html
│   ├── index.html
│   ├── docs.html
│   ├── examples.html
│   └── styles.css
├── package.json
├── pnpm-lock.yaml
└── vite.config.js

Example element file:

<!-- elements/header.html -->
<header class="bg-primary-600 p-4">
  <nav class="flex justify-between items-center">
    <a href="/">Home</a>
    <a href="/docs">Docs</a>
  </nav>
</header>

Include elements in your HTML files using the <element /> tag:

<!doctype html>
<html>
  <body>
    <element src="header.html" />
    
    <main>
      <h1>Your content</h1>
    </main>
    
    <element src="footer.html" />
  </body>
</html>

Options

debug

Type: boolean

Default: false

Enable verbose logging to see which elements are being included during build.

htmlElements({ debug: true })

Slots and Props

Using Slots

Slots let you inject dynamic content into reusable elements. Use <slot /> as a placeholder:

<!-- elements/card.html -->
<div class="bg-white rounded-lg shadow-md p-6">
  <slot />
</div>
<!-- Usage -->
<element src="card.html">
  <h2>Card Title</h2>
  <p>Card content goes here</p>
  <button>Click me</button>
</element>

Using Props

Pass string values to elements using props. Define placeholders with {{propName}}:

<!-- elements/hero.html -->
<section class="{{className}}">
  <h1>{{title}}</h1>
  <p>{{subtitle}}</p>
  <slot />
</section>
<!-- Usage -->
<element 
  src="hero.html" 
  title="Welcome to My Site"
  subtitle="Build fast static sites"
  className="bg-blue-500 text-white p-8"
>
  <button>Get Started</button>
</element>

Common Patterns

Shared Head Element

Keep meta tags, stylesheets, and scripts consistent across all pages:

<!-- elements/head.html -->
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="/styles.css" />
  <title>{{pageTitle}}</title>
</head>

<!-- Usage -->
<element src="head.html" pageTitle="Home | My Site" />

Feature Cards with Icons

Reusable cards with props and slots for flexible content:

<!-- elements/feature-card.html -->
<div class="bg-secondary-800 rounded-lg p-6">
  <div class="text-3xl mb-3">{{icon}}</div>
  <h3 class="text-xl font-semibold mb-2">{{title}}</h3>
  <slot />
</div>

<!-- Usage -->
<element src="feature-card.html" icon="⚡" title="Fast Builds">
  <p>Lightning-fast hot reloading with Vite.</p>
</element>

Flexible Section Layout

Create consistent section layouts with customizable titles:

<!-- elements/section.html -->
<section class="py-16">
  <div class="container mx-auto">
    <h2 class="text-3xl font-bold mb-8">{{title}}</h2>
    <slot />
  </div>
</section>

<!-- Usage -->
<element src="section.html" title="Our Services">
  <div class="grid grid-cols-3 gap-6">
    <!-- Service cards here -->
  </div>
</element>

Button Components

Consistent button styles with customizable variants:

<!-- elements/button.html -->
<button class="px-6 py-3 rounded-lg {{variant}}">
  <slot />
</button>

<!-- Usage -->
<element src="button.html" variant="bg-blue-500 text-white">
  Get Started
</element>

<element src="button.html" variant="bg-gray-200 text-gray-800">
  Learn More
</element>

FAQ

Does it work with other Vite plugins?

Yes! It's fully compatible with other Vite plugins like Tailwind CSS.

Can elements include JavaScript?

Elements are just HTML. You can include <script> tags in your elements if needed.

What about dynamic content?

This plugin is for static composition. For dynamic content, layer on JavaScript after your HTML is built.

How does path resolution work?

Element paths are relative to src/elements/ by default. You can organize with subdirectories:

<element src="components/nav.html" />
<element src="layouts/base.html" />