npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ladrillosjs

v2.0.0-beta.6

Published

A lightweight, zero-dependency web component framework for building modular web applications.

Readme

LadrillosJS


📑 Table of Contents


🚀 Quick Start

1. Add the Script

<script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>

2. Create a Component

Save this as counter.html:

<div class="counter">
  <div class="count-display">{count}</div>
  <div class="buttons">
    <button onclick="count--">−</button>
    <button onclick="count = 0">Reset</button>
    <button onclick="count++">+</button>
  </div>
  <p>Double: {count * 2} | Squared: {count * count}</p>
</div>

<script>
  let count = 0;
</script>

<style>
  .counter {
    text-align: center;
    padding: 2rem;
  }
  .count-display {
    font-size: 4rem;
    font-weight: bold;
  }
  button {
    padding: 0.5rem 1rem;
    margin: 0.25rem;
    cursor: pointer;
  }
</style>

3. Use It

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
    <script type="module">
      ladrillosjs.registerComponent("my-counter", "./counter.html");
    </script>
  </head>
  <body>
    <my-counter></my-counter>
  </body>
</html>

That's it! Your reactive component is ready. 🎉


📦 Installation

CDN (No Build Step)

<!-- Global (UMD) -->
<script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
<script type="module">
  ladrillosjs.registerComponent("my-component", "./component.html");
</script>

<!-- ES Module -->
<script type="module">
  import { registerComponent } from "https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.es.js";
  registerComponent("my-component", "./component.html");
</script>

NPM (With Build Tools)

npm install ladrillosjs
import { registerComponent, registerComponents } from "ladrillosjs";

// Single component
registerComponent("my-counter", "./components/counter.html");

// Multiple components
await registerComponents([
  { name: "app-header", path: "./components/header.html" },
  { name: "app-footer", path: "./components/footer.html" },
]);

📖 Core Concepts

Template Bindings

Use {expression} to display reactive data. Any JavaScript expression works:

<h1>{title}</h1>
<p>Hello, {user.name}!</p>
<span>Total: {items.length} items</span>
<p>Is adult: {age >= 18 ? 'Yes' : 'No'}</p>

Reactive State

Just declare variables with let — changes automatically update the DOM:

<script>
  let count = 0;
  let user = { name: "Alice", role: "Developer" };
  let items = ["Apple", "Banana", "Cherry"];
</script>

Event Handlers

Attach events directly in HTML with inline expressions or function calls:

<button onclick="count++">Increment</button>
<button onclick="handleClick()">Click me</button>
<input onkeyup="search(event.target.value)" />
<form onsubmit="handleSubmit(event)">...</form>

Two-Way Binding

Use $bind to sync form inputs with state:

<input type="text" $bind="username" placeholder="Enter name" />
<p>Hello, {username}!</p>

<textarea $bind="bio"></textarea>

<select $bind="country">
  <option value="us">United States</option>
  <option value="uk">United Kingdom</option>
</select>

<script>
  let username = "";
  let bio = "";
  let country = "us";
</script>

🧩 Directives

Conditional Rendering

Use $if, $else-if, and $else to conditionally render elements:

<div $if="{status === 'loading'}">Loading...</div>
<div $else-if="{status === 'error'}">Something went wrong!</div>
<div $else>Content loaded successfully!</div>

<script>
  let status = "loading";
</script>

Show/Hide (CSS Toggle)

Use $show to toggle visibility without removing from DOM (uses display: none):

<div $show="{isVisible}">I can be shown or hidden</div>

<button onclick="isVisible = !isVisible">Toggle</button>

<script>
  let isVisible = true;
</script>

$show vs $if: $show toggles CSS display (element stays in DOM), $if adds/removes from DOM entirely.

List Rendering

Use $for to render lists with optional index and key:

<!-- Simple list -->
<ul>
  <li $for="fruit in fruits">🍎 {fruit}</li>
</ul>

<!-- With index -->
<div $for="(item, index) in items">#{index + 1}: {item}</div>

<!-- Object array with key -->
<div $for="user in users" $key="user.id">
  <span>{user.avatar}</span>
  <span>{user.name}</span>
  <span>{user.role}</span>
</div>

<script>
  let fruits = ["Apple", "Banana", "Cherry"];
  let items = ["First", "Second", "Third"];
  let users = [
    { id: 1, name: "Alice", role: "Developer", avatar: "👩‍💻" },
    { id: 2, name: "Bob", role: "Designer", avatar: "👨‍🎨" },
  ];
</script>

Directives Cheat Sheet

| Directive | Purpose | Example | | ---------------- | --------------------- | ------------------------------------------------ | | $if | Conditional render | <div $if="{isLoggedIn}">Welcome!</div> | | $else-if | Chained condition | <div $else-if="{isGuest}">Hello Guest</div> | | $else | Fallback | <div $else>Please log in</div> | | $show | CSS visibility toggle | <div $show="{isOpen}">Menu</div> | | $for | Loop rendering | <li $for="item in items">{item}</li> | | $for (indexed) | Loop with index | <li $for="(item, i) in items">{i}: {item}</li> | | $bind | Two-way binding | <input $bind="email" /> | | $key | List optimization | <div $for="user in users" $key="user.id"> | | $ref | Element reference | <input $ref="inputEl" /> |


📡 Event Bus

Communicate between components using $emit and $listen:

Sender Component

<button onclick="sendMessage()">Send Message</button>

<script>
  let message = "Hello from sender!";

  function sendMessage() {
    $emit("my-event", { text: message, time: new Date().toLocaleTimeString() });
  }
</script>

Receiver Component

<div>
  <p>Received: {receivedMessage}</p>
</div>

<script>
  let receivedMessage = "Waiting...";

  $listen("my-event", (data) => {
    receivedMessage = data.text;
  });
</script>

🏷️ Element References

Use $ref to get direct DOM access for advanced manipulation:

<input type="text" $ref="inputEl" placeholder="Click button to focus" />
<button onclick="focusInput()">Focus Input</button>

<canvas $ref="canvas" width="200" height="100"></canvas>
<button onclick="draw()">Draw on Canvas</button>

<script>
  function focusInput() {
    $refs.inputEl.focus();
    $refs.inputEl.select();
  }

  function draw() {
    const ctx = $refs.canvas.getContext("2d");
    ctx.fillStyle = "blue";
    ctx.fillRect(10, 10, 100, 50);
  }
</script>

⏳ Lazy Loading

Load components only when needed to improve initial page load:

Lazy Loading Strategies

import {
  registerComponents,
  lazyOnVisible,
  lazyOnIdle,
  lazyOnInteraction,
  lazyOnMedia,
  lazyOnDelay,
} from "ladrillosjs";

await registerComponents([
  // Load when visible in viewport
  {
    name: "lazy-footer",
    path: "./footer.html",
    lazy: lazyOnVisible({ rootMargin: "100px" }),
  },

  // Load when browser is idle
  {
    name: "analytics-widget",
    path: "./analytics.html",
    lazy: lazyOnIdle(5000), // timeout: 5s max wait
  },

  // Load on user interaction
  {
    name: "modal-dialog",
    path: "./modal.html",
    lazy: lazyOnInteraction(["click", "focusin"]),
  },

  // Load based on media query
  {
    name: "mobile-nav",
    path: "./mobile-nav.html",
    lazy: lazyOnMedia("(max-width: 768px)"),
  },

  // Load after delay
  {
    name: "chat-widget",
    path: "./chat.html",
    lazy: lazyOnDelay(3000), // 3 second delay
  },
]);

| Strategy | Use Case | | ------------------- | -------------------------------------------- | | lazyOnVisible | Below-fold content, footers, image galleries | | lazyOnIdle | Non-critical features, analytics | | lazyOnInteraction | Modals, dropdowns, tooltips | | lazyOnMedia | Mobile/desktop specific components | | lazyOnDelay | Chat widgets, notifications |

Eager Override

Force a lazy component to load immediately by adding the eager attribute:

<lazy-footer eager></lazy-footer>

📋 API Reference

registerComponent

registerComponent(name, path, useShadowDOM?, lazy?)

| Parameter | Type | Default | Description | | -------------- | ----------------------- | -------- | ------------------------------- | | name | string | required | Tag name (must include hyphen) | | path | string | required | Path to .html component file | | useShadowDOM | boolean | true | Enable Shadow DOM encapsulation | | lazy | boolean | LazyStrategy | false | Lazy loading configuration |

// Basic usage
registerComponent("my-button", "./button.html");

// Without Shadow DOM (for global CSS)
registerComponent("my-nav", "./nav.html", false);

// With lazy loading
registerComponent("my-footer", "./footer.html", true, lazyOnVisible());

registerComponents

Register multiple components with parallel fetching:

const result = await registerComponents([
  { name: "app-header", path: "./header.html" },
  { name: "app-footer", path: "./footer.html", lazy: lazyOnVisible() },
  { name: "user-card", path: "./user-card.html", useShadowDOM: false },
]);

// Returns: { success: [...], failed: [...], skipped: [...] }

Event Bus

| Function | Description | | -------------------------- | ----------------------------------- | | $emit(event, data) | Broadcast an event to all listeners | | $listen(event, callback) | Subscribe to an event |


🛠️ Using with Vite

LadrillosJS works seamlessly with Vite for production builds:

npm install ladrillosjs vite
// vite.config.js
import { defineConfig } from "vite";

export default defineConfig({
  // LadrillosJS components work out of the box!
});
// main.js
import { registerComponent } from "ladrillosjs";

registerComponent("my-counter", "./components/counter.html", false);

See the samples/ directory for complete examples:

  • samples/vite-sample/ — Basic Vite setup
  • samples/vite-basic-site/ — Multi-component site
  • samples/ladrillos-demo/ — Full feature showcase

📚 Examples

Todo List

A complete CRUD example combining all directives:

<div class="todo-app">
  <form onsubmit="addTodo(event)">
    <input type="text" $bind="newTodo" placeholder="What needs to be done?" />
    <button type="submit">Add</button>
  </form>

  <ul>
    <li $for="todo in todos" $key="todo.id">
      <input type="checkbox" onclick="toggleTodo({todo.id})" />
      <span class="{todo.completed ? 'done' : ''}">{todo.text}</span>
      <button onclick="removeTodo({todo.id})">🗑️</button>
    </li>
  </ul>

  <p $if="{todos.length === 0}">No todos yet!</p>
</div>

<script>
  let todos = [
    { id: 1, text: "Learn LadrillosJS", completed: false },
    { id: 2, text: "Build something awesome", completed: false },
  ];
  let newTodo = "";
  let nextId = 3;

  function addTodo(event) {
    event.preventDefault();
    if (newTodo.trim()) {
      todos = [...todos, { id: nextId++, text: newTodo, completed: false }];
      newTodo = "";
    }
  }

  function toggleTodo(id) {
    todos = todos.map((t) =>
      t.id === id ? { ...t, completed: !t.completed } : t
    );
  }

  function removeTodo(id) {
    todos = todos.filter((t) => t.id !== id);
  }
</script>

💡 Check the samples/ folder for more examples including lazy loading, event bus communication, and real-world patterns.


🤝 Contributing

Contributions are welcome! Here's how you can help:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Development Setup

git clone https://github.com/drubiodev/LadrillosJS.git
cd LadrillosJS
npm install
npm run dev        # Watch mode for development
npm run build      # Build for production

📄 License

MIT License — see LICENSE for details.