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).
Keep your HTML DRY without framework overhead. Compose reusable components at build time with zero runtime JavaScript.
Or install the plugin manually:
npm install -D vite-plugin-html-elements
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()]
});
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>
Type:
boolean
Default:
false
Enable verbose logging to see which elements are being included during build.
htmlElements({ debug: true })
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>
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>
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" />
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>
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>
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>
Yes! It's fully compatible with other Vite plugins like Tailwind CSS.
Elements are just HTML. You can include
<script>
tags in your elements if needed.
This plugin is for static composition. For dynamic content, layer on JavaScript after your HTML is built.
Element paths are relative to
src/elements/
by default. You can organize with subdirectories:
<element src="components/nav.html" />
<element src="layouts/base.html" />