DEV Community

Nakassony Bernardo
Nakassony Bernardo

Posted on • Edited on

Still.js - A way to leverage Vanilla JavaScript for Complex and Enterprise Level Web Development

Image description

When it comes to complex web application development on the frontend, we often encounter the need to implement features using vanilla JavaScript—whether it’s for direct DOM manipulation or integrating a specific jQuery plugin. Sometimes, a from-scratch implementation using plain HTML, CSS, and vanilla JavaScript is the best (or only) choice.

What is Still.js

Still.js is a modern framework that offers the same capabilities as Angular, React, and Vue—without abandoning vanilla JavaScript.

Because of its pure JS approach, Still.js:

  • Does not require preprocessing
  • Does not depend on bundlers like Webpack or Vite
  • Is ideal for teams and developers who prefer direct, no-compromise access to native web technologies.

Check it up:

Suitable for complex and enterprise applications

Enterprise-grade web applications need more than just rich UI features. They require: modularization, user permission management, component routing, validation, separation of concern, communication management, Micro-frontend architecture (e.g. Frontend embedding and interaction), and more.

Still.js supports all of this features natively without the burden of a bundler increasing build time and potential complexity or even tooling overhead.

Some code samples

📌 Note: Those will only work within a Still.js project with the correct setup, which is thoroughly explained in the official documentation.

Basic component:
Bellow is a simple component implementing a counter, inspite the template is placed inside the class, it can be moved to a .html file which is appropriate in complex apps.

export class CounterComponent extends ViewComponent {

    isPublic = true;
    count = 0;

    template = `
    <div>
        <p>My counter state is @count</p>
        <button (click)="increment()">Increment (@count)</button>
    </div>
    `;

    increment() {
        this.count = this.count.value + 1;
    }
}
Enter fullscreen mode Exit fullscreen mode

Basic User authorization management
In the bellow implementation we're stating that some components won't be accessible by the user, this can be done with proper business logic according to the user role checking.

import { StillAppMixin } from "./@still/component/super/AppMixin.js";
import { Components } from "./@still/setup/components.js";
import { AppTemplate } from "./app-template.js";
import { CheckingAccount } from "./app/components/BankAccount/CheckingAccount.js";
import { NewAccountForm } from "./app/components/BankAccount/NewAccountForm.js";
import { SavingAccount } from "./app/components/BankAccount/SavingAccount.js";

export class StillAppSetup extends StillAppMixin(Components) {

    constructor() {
        super();
        //Bellow the entry point component is being set
        this.setHomeComponent(NewAccountForm);
        const blackListComponents = [SavingAccount, CheckingAccount];
        //Make components black-listed by passing it to setBlackList App configuration
        this.setBlackList(blackListComponents);
    }

    async init() {
        return await AppTemplate.newApp();
    }

}
Enter fullscreen mode Exit fullscreen mode

Basic Form validation
Still.js provides built-in validators, but custom ones can be implemented effortlessly.

import { ViewComponent } from "../../../@still/component/super/ViewComponent.js";

export class BasicForm extends ViewComponent {

    isPublic = true;
    firstName = '';
    shoeSize;

    template = `
    <div>
        <form>
            <div class="form-group">
                <label>Shoe Size</label>
                <input 
                    (value)="shoeSize" 
                    (validator)="number" 
                    (validator-warn)="Invalid shoe size, number is required"
                    placeholder="Enter valid shoe size"
                >
            </div>
        </form>
    </div>
    `;

}
Enter fullscreen mode Exit fullscreen mode

Global State management
A service serves for both Global reactive storage and data flow (e.g. HTTP requests) implementations. Services path can be set in the application level, and we can overriden for specific service with @Path annotation.

import { ViewComponent } from "../../../@still/component/super/ViewComponent.js";
import { CustomersService } from "../../service/api/CustomersService.js";

export class BiddingDisplay extends ViewComponent {

    isPublic = true;

    /** Service declaration, will get injected automatically due to Inject anottation
     *  from the specified Path path due to the annotation
     * @Inject
     * @Path service/api/
     * @type { CustomersService } */
    custService;

    template = `<div></div>`;

    /** Component Hook which takes place when it's completly render and startder */
    stAfterInit() {

        this.custService.customerList.onChange((newValue) => { 
            console.log('Ths customerList store got updated with: ', newValue);
        });

    }

}
Enter fullscreen mode Exit fullscreen mode

Hurry up, get yourself started with Still.js

Still.js is available through NPM on @stilljs/cli. Watch the Youtube ▶️ playlist and bear for more coming ones.

Watch this Tudo App tutorial on Youtube ▶️, clone or download the provided GitHub Todo app project and run locally. It demonstrates key concepts like component communication, event and state binding, reactive updates, @Proxy, and component styling.

Connect and share your feedback on the Discord channel.

Top comments (0)