A truly modest yet powerful JavaScript framework.
npm install simplicitSimplicit is a small library for structuring front-end JavaScript around controllers and components.
On the MVC side, it mirrors the “controller/action” convention you may know from frameworks like Ruby on Rails: based on attributes, it finds the corresponding controller and calls its lifecycle hooks and action method.
On the component side, it provides a lightweight runtime (start() + Component) that instantiates and binds components from data-component, builds parent/child relationships, and automatically tears them down when elements are removed from the DOM.
Simplicit relies only on dompurify for sanitizing HTML.
``bash`
$ npm install --save simplicit
Simplicit ships with a small component runtime built around DOM attributes.
`javascript
import { start, Component } from "simplicit";
class Hello extends Component {
static name = "hello";
connect() {
const { input, button, output } = this.refs();
this.on(button, "click", () => {
output.textContent = Hello ${input.value}!;
});
}
}
document.addEventListener("DOMContentLoaded", () => {
start({ root: document, components: [Hello] });
});
`
`html`
* data-component="
* must match the component class’ static name.
*
`
Notes:
* The JSON payload must be an array; each item is passed to ComponentClass.template(item).dompurify
* The rendered HTML is sanitized with before being inserted.data-target
* must match an existing element id, otherwise an error is thrown.targetEl.insertAdjacentHTML(position, html)
* Insertion uses where position comes from data-position (default: beforeend). Valid values: beforebegin, afterbegin, beforeend, afterend.
* Inserted component elements are then auto-initialized like any other DOM addition.
Simplicit must have access to all controllers you want to run. In practice, you build a Controllers object and pass it to init().
_Example:_
`javascript
// js/index.js (entry point)
import { init } from 'simplicit';
import Admin from "./controllers/Admin.js"; // namespace controller
import User from "./controllers/User.js"; // namespace controller
import Articles from "./controllers/admin/Articles.js";
import Comments from "./controllers/admin/Comments.js";
Object.assign(Admin, {
Articles,
Comments
});
const Controllers = {
Admin,
User
};
document.addEventListener("DOMContentLoaded", function() {
init(Controllers);
});
`
Example controller:
`javascript
// js/controllers/admin/Articles.js
import { helpers } from "simplicit";
import Index from "views/admin/articles/Index.js";
import Show from "views/admin/articles/Show.js";
class Articles {
// Simplicit supports both static and instance actions
static index() {
Index.render();
}
show() {
Show.render({ id: helpers.params.id });
}
}
export default Articles;
`
Minimal view example (one possible approach):
`javascript
// views/admin/articles/Show.js
export default {
render: ({ id }) => {
const el = document.getElementById("app");
el.textContent = Article ${id};`
// If you need data loading, you can fetch here and update the DOM after.
},
};
On DOMContentLoaded, Simplicit reads these
attributes:*
data-namespace (optional): a namespace path like Main or Main/Panel
* data-controller: controller name (e.g. Pages)
* data-action: action name (e.g. index)`html
`Then it resolves the matching controller(s), runs lifecycle hooks, and calls the action.
Resolution rules (simplified):
* If
data-namespace resolves (e.g. Main/Panel → Controllers.Main.Panel), Simplicit initializes the namespace controller and resolves the page controller under it (e.g. Controllers.Main.Panel.Pages).
* Otherwise it skips the namespace controller and falls back to Controllers.Pages.Call order (per controller):
* If a method exists as static or instance, Simplicit will call it.
* On navigation/re-init, previously active controllers receive
deinitialize() (if present).`javascript
namespaceController = new Controllers.Main.Panel;
Controllers.Main.Panel.initialize(); // if exists
namespaceController.initialize(); // if existscontroller = new Controllers.Main.Panel.Pages;
Controllers.Main.Panel.Pages.initialize(); // if exists
controller.initialize(); // if exists
Controllers.Main.Panel.Pages.index(); // if exists
controller.index(); // if exists
`You don’t need controllers for every page; if a controller/method is missing, Simplicit skips it.
The
init function returns { namespaceController, controller, action }.🛠 Helpers
Simplicit exports
helpers object that has the following properties:* params (getter) - facilitates fetching params from the URL
👩🏽🔬 Tests
`bash
npx playwright installnpm run test
npx playwright test --headed e2e/slideshow.spec.js
``Simplicit is released under the MIT License.
Zbigniew Humeniuk from Art of Code