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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rasti

v4.0.0

Published

Modern MVC for building user interfaces

Downloads

776

Readme

Rasti is a lightweight MVC library for building fast, reactive user interfaces.
It provides declarative, composable components for building state-driven UIs.
Its low-level MVC core, inspired by Backbone.js’s architecture, provides models, views and event emitters as the fundamental building blocks.

Travis (.com) npm version npm package minimized gzipped size npm downloads jsDelivr hits (npm)

Key Features

  • Declarative Components 🌟
    Build dynamic UI components using intuitive template literals.
  • Event Delegation 🎯
    Simplify event handling with built-in delegation.
  • Model-View Binding 🔗
    Keep your UI and data in sync with ease.
  • Server-Side Rendering 🌐
    Render as plain text for server-side use or static builds.
  • Lightweight and Fast
    Minimal overhead with efficient rendering.
  • Legacy Compatibility 🕰️
    Seamlessly integrates into existing Backbone.js legacy projects.
  • Standards-Based 📐
    Built on modern web standards, no tooling required.

Getting Started

Installing via npm

$ npm install rasti
import { Model, Component } from 'rasti';

Using ES modules via CDN

import { Model, Component } from 'https://esm.run/rasti';

Using a UMD build via CDN

Include Rasti directly in your HTML using a CDN. Available UMD builds:

<script src="https://cdn.jsdelivr.net/npm/rasti"></script>

The UMD build exposes the Rasti global object:

const { Model, Component } = Rasti;

Create a Component

// Define a Timer component that displays the number of seconds from the model.
const Timer = Component.create`
    <div>
        Seconds: <span>${({ model }) => model.seconds}</span>
    </div>
`;

// Create a model to store the seconds.
const model = new Model({ seconds : 0 });

// Mount the Timer component to the body and pass the model as an option.
Timer.mount({ model }, document.body);

// Increment the `seconds` property of the model every second.
// Only the text node inside the <span> gets updated on each render.
setInterval(() => model.seconds++, 1000);

Try it on CodePen

Adding sub components

// Define the routes for the navigation menu.
const routes = [
    { label : 'Home', href : '#' },
    { label : 'Faq', href : '#faq' },
    { label : 'Contact', href : '#contact' },
];

// Create a Link component for navigation items.
const Link = Component.create`
    <a href="${({ props }) => props.href}">
        ${({ props }) => props.renderChildren()}
    </a>
`;

// Create a Navigation component that renders Link components for each route.
const Navigation = Component.create`
    <nav>
        ${({ props, partial }) => props.routes.map(
            ({ label, href }) => partial`<${Link} href="${href}">${label}</${Link}>`
        )}
    </nav>
`;

// Create a Main component that includes the Navigation and displays the current route's label as the title.
const Main = Component.create`
    <main>
        <${Navigation} routes=${({ props }) => props.routes} />
        <section>
            <h1>
                ${({ model, props }) => props.routes.find(
                    ({ href }) => href === (model.location || '#')
                ).label}
            </h1>
        </section>
    </main>
`;

// Initialize a model to store the current location.
const model = new Model({ location : document.location.hash });

// Update the model's location state when the browser's history changes.
window.addEventListener('popstate', () => model.location = document.location.hash);

// Mount the Main component to the body, passing the routes and model as options.
Main.mount({ routes, model }, document.body);

Try it on CodePen

Adding event listeners

// Create a model to store the counter value.
const model = new Model({ count : 0 });

// Create a Counter component with increment and decrement buttons.
const Counter = Component.create`
    <div>
        <div>Counter: ${({ model }) => model.count}</div>
        <button onClick=${function() { this.model.count++; }}>Increment</button>
        <button onClick=${function() { this.model.count--; }}>Decrement</button>
    </div>
`;

// Mount the Counter component to the body and pass the model as an option.
Counter.mount({ model }, document.body);

// Event listeners are bound to 'this' and use delegation from the root element.
// When buttons are clicked, only the text node gets updated, not the entire component.

Try it on CodePen

Why Choose Rasti?

Rasti is built for developers who want a simple yet powerful way to create UI components without the complexity of heavy frameworks. Whether you're building a high-performance dashboard, or embedding a lightweight widget, Rasti lets you:

  • Skip the Setup
    No installations, no build tools—just load it and start coding.
  • Lightweight and Efficient
    Minimal footprint with optimized performance, ensuring smooth updates.
  • Just the Right Abstraction
    Keeps you close to the DOM with no over-engineering. Fully hackable—if you're curious about how something works, just check the source code.

Example

You can find a sample TODO application in the example folder of the Rasti GitHub repository. This example serves as a great starting point for your own projects. Try it live here.

API Documentation

For detailed information on how to use Rasti, refer to the API documentation.

Working with LLMs

For those working with LLMs, there is an AI Agents reference guide that provides API patterns, lifecycle methods, and best practices, optimized for LLM context. You can share this guide with AI assistants to help them understand Rasti's architecture and component APIs.

Version History

We strive to minimize breaking changes between major versions. However, if you're migrating between major versions, please refer to the release notes below for details on any breaking changes and migration tips.

License

Rasti is open-source and available under the MIT License.

Contributing

Contributions are welcome! Share feature ideas or report bugs on our GitHub Issues page.