HTML-COMPO.js

Create reusable HTML components with ease

Installation

HTML-COMPO.js is a lightweight library for creating reusable HTML components without any build tools or complex setup.

CDN
NPM
Download
<script src="https://cdn.jsdelivr.net/npm/html-compo@latest/src/main.js"></script>
npm install html-compo

Then include in your project:

import 'html-compo';

Download the latest version from GitHub and include it in your project:

<script src="path/to/html-compo.js"></script>

Quick Start

Get started with HTML-COMPO.js in just a few steps:

1. Include the library

<script src="https://cdn.jsdelivr.net/npm/html-compo@latest/src/main.js"></script>

2. Define your components

<html-components>
  <user-card>
    <div class="card">
      <h3>@{self.data}</h3>
    </div>
  </user-card>
</html-components>

3. Use your components

<user-card>John Doe</user-card>
<user-card>Jane Smith</user-card>
John Doe Jane Smith

Basic Usage

Component Definition Container

Use <html-components> or the shorter <h-c> tag to define your components:

<html-components>
  <my-button>
    <button class="btn">@{self.data}</button>
  </my-button>
</html-components>

<!-- Alternative shorter syntax -->
<h-c>
  <my-button>
    <button class="btn">@{self.data}</button>
  </my-button>
</h-c>

Template Variables

Use @{variable} syntax to insert dynamic content:

@{self.data}

The content inside the component tag when used

@{self.componentName}

The tag name of the component

@{attributeName}

Values from component attributes (when using compo-attrs)

Basic Example

<greeting-card>Hello, World!</greeting-card>
<greeting-card>Welcome to HTML-COMPO.js</greeting-card>

<html-components>
  <greeting-card>
    <div class="greeting">
      <h2>🎉 @{self.data} 🎉</h2>
      <p>This is a @{self.componentName} component!</p>
    </div>
  </greeting-card>
</html-components>
Hello, World! Welcome to HTML-COMPO.js

Component Attributes

Using compo-attrs

The compo-attrs attribute allows you to specify which attributes should be passed as variables to your component template:

<user-profile name="John Doe" email="[email protected]" role="Admin"></user-profile>
<user-profile name="Jane Smith" email="[email protected]" role="User"></user-profile>

<html-components>
  <user-profile compo-attrs="name,email,role">
    <div class="profile">
      <h3>@{name}</h3>
      <p>Email: @{email}</p>
      <p>Role: @{role}</p>
    </div>
  </user-profile>
</html-components>

Default Attribute Values

You can provide default values for attributes using the attributeName=defaultValue syntax:

<product-card name="Laptop" price="999"></product-card>
<product-card name="Phone"></product-card> <!-- Uses default price -->

<html-components>
  <product-card compo-attrs="name,price=599">
    <div class="product">
      <h4>@{name}</h4>
      <p>Price: $@{price}</p>
    </div>
  </product-card>
</html-components>

Shadow DOM Support

HTML-COMPO.js supports Shadow DOM encapsulation using the fragment="true" attribute:

<style>
  .shadow-demo { color: red; font-size: 20px; }
</style>

<shadow-component>This text won't be affected by external styles</shadow-component>
<div class="shadow-demo">This text will be red and large</div>

<html-components>
  <shadow-component fragment="true">
    <style>
      .shadow-demo { color: blue; font-size: 14px; }
    </style>
    <div class="shadow-demo">@{self.data}</div>
  </shadow-component>
</html-components>
Note: When using Shadow DOM, styles defined within the component are encapsulated and won't affect the rest of the page.
This text won't be affected by external styles
This text will be red and large

API Reference

Global API

HTML-COMPO.js exposes a global htmlCompo object with the following methods:

htmlCompo.getComponent(reference: string): HtmlCompoFunc | null

Gets a component instance by its reference attribute.

reference string - The value of the ref attribute

Returns: An HtmlCompoFunc instance or null if not found

HtmlCompoFunc Class

Returned by getComponent(), provides methods to manipulate components:

html(): string
html(content: string): void

Gets or sets the HTML content of the component.

attr(name: string): string | null
attr(name: string, value: string): void

Gets or sets an attribute of the component.

Using Component References

<my-counter ref="counter1" count="0"></my-counter>
<button onclick="incrementCounter()">Increment</button>

<script>
function incrementCounter() {
  const counter = htmlCompo.getComponent('counter1');
  if (counter) {
    const currentCount = parseInt(counter.attr('count')) + 1;
    counter.attr('count', currentCount);
    counter.html(`Count: ${currentCount}`);
  }
}
</script>

<html-components>
  <my-counter compo-attrs="count">
    Count: @{count}
  </my-counter>
</html-components>

Advanced Examples

Todo List Component

<todo-item task="Buy groceries" completed="false"></todo-item>
<todo-item task="Walk the dog" completed="true"></todo-item>

<html-components>
  <todo-item compo-attrs="task,completed=false">
    <div class="todo-item" style="margin: 10px 0; padding: 10px; border: 1px solid #ddd;">
      <input type="checkbox" @{completed === 'true' ? 'checked' : ''}>
      <span style="@{completed === 'true' ? 'text-decoration: line-through; color: #999;' : ''}">
        @{task}
      </span>
    </div>
  </todo-item>
</html-components>

Card Component with Slots

<info-card title="Welcome" type="success">
  This is a success message with <strong>HTML content</strong>!
</info-card>

<info-card title="Warning" type="warning">
  Please check your input carefully.
</info-card>

<html-components>
  <info-card compo-attrs="title,type=info">
    <div style="border: 2px solid; padding: 15px; margin: 10px 0; border-radius: 5px;
                border-color: @{type === 'success' ? '#4caf50' : type === 'warning' ? '#ff9800' : '#2196f3'};
                background-color: @{type === 'success' ? '#e8f5e8' : type === 'warning' ? '#fff3e0' : '#e3f2fd'};">
      <h4 style="margin: 0 0 10px 0; color: @{type === 'success' ? '#2e7d32' : type === 'warning' ? '#ef6c00' : '#1565c0'};">
        @{title}
      </h4>
      <div>@{self.data}</div>
    </div>
  </info-card>
</html-components>
This is a success message with HTML content! Please check your input carefully.

Navigation Menu

<nav-menu>
  <nav-item href="#home">Home</nav-item>
  <nav-item href="#about">About</nav-item>
  <nav-item href="#contact" active="true">Contact</nav-item>
</nav-menu>

<html-components>
  <nav-menu>
    <ul style="list-style: none; display: flex; gap: 0; margin: 0; padding: 0; background: #333;">
      @{self.data}
    </ul>
  </nav-menu>
  
  <nav-item compo-attrs="href,active=false">
    <li>
      <a href="@{href}" 
         style="display: block; padding: 15px 20px; color: white; text-decoration: none;
                background: @{active === 'true' ? '#555' : 'transparent'};
                border-bottom: @{active === 'true' ? '3px solid #007bff' : 'none'};">
        @{self.data}
      </a>
    </li>
  </nav-item>
</html-components>
Home About Contact

TypeScript Support

HTML-COMPO.js includes full TypeScript support with type definitions and a TypeScript source version.

Installation with TypeScript

npm install html-compo
npm install -D typescript

Type Definitions

The library provides comprehensive type definitions:

interface HtmlCompoAPI {
  getComponent(reference: string): HtmlCompoFunc | null;
}

declare global {
  interface Window {
    htmlCompo: HtmlCompoAPI;
  }
}

class HtmlCompoFunc {
  html(): string;
  html(content: string): void;
  attr(name: string): string | null;
  attr(name: string, value: string): void;
}

Usage in TypeScript

// Type-safe component access
const component = window.htmlCompo.getComponent('my-ref');
if (component) {
  // TypeScript knows these methods exist and their signatures
  const content: string = component.html();
  component.attr('class', 'new-class');
}
Note: The TypeScript version maintains full compatibility with the JavaScript version while providing compile-time type checking and better IDE support.

Best Practices

📝 Naming Convention

Use kebab-case for component names (e.g., user-card, nav-item)

🎯 Keep Components Simple

Each component should have a single responsibility and be reusable

📦 Use Attributes Wisely

Leverage compo-attrs for configurable components with sensible defaults

🔒 Consider Shadow DOM

Use fragment="true" when you need style encapsulation

🏷️ Use References

Add ref attributes to components you need to manipulate with JavaScript

⚡ Performance

Define components early in your HTML for optimal performance

@{self.data}

🎉 @{self.data} 🎉

This is a @{self.componentName} component!

@{name}

Email: @{email}

Role: @{role}

@{name}

Price: $@{price}

@{self.data}
Count: @{count}
@{task}

@{title}

@{self.data}
  • @{self.data}