amish-js
v1.1.0
Published
Seamless SSR page transitions + simple DOM controllers. No build step.
Maintainers
Readme
amish-js
A return to a simpler time.
I visited a website the other day. The checkboxes didn't work. I opened devtools to find 14 megabytes of JavaScript responsible for rendering them. Fourteen megabytes. For checkboxes.
Checkboxes worked in 1994. They worked without JavaScript. They worked on a 28.8k modem. What happened?
We fucked up. Somewhere along the way, we convinced ourselves that complexity is progress. That you need a virtual DOM to toggle a boolean. That "developer experience" means waiting for webpack to compile.
amish-js is the mass exodus back to sanity:
<link rel="stylesheet" href="amish.css">
<script src="amish.js" defer></script>- View transitions between server-rendered pages — no SPA required
- DOM controllers that attach behavior to HTML — no virtual DOM, no reactivity tax
- ~100 lines of JS — read it, understand it, own it
Your pages already work. This just makes them smoother.
Install
Copy to your project:
npx amish-js ./publicOr use a CDN:
<link rel="stylesheet" href="https://unpkg.com/amish-js/amish.css">
<script src="https://unpkg.com/amish-js/amish.js" defer></script>Then add the view transition meta tag:
<meta name="view-transition" content="same-origin">View Transitions
Elements with .amish-persist-* classes stay in place across page navigations:
<header class="amish-persist-header">...</header>
<nav class="amish-persist-nav">...</nav>
<aside class="amish-persist-sidebar">...</aside>
<footer class="amish-persist-footer">...</footer>
<!-- Generic persist for any element -->
<div class="amish-persist">...</div>Add a loading bar:
<div class="amish-loader"></div>Controllers
Attach behavior to elements with the controller attribute:
<div controller="counter">
<span class="count">0</span>
<button class="inc">+</button>
<button class="dec">-</button>
</div>Define a controller:
class Counter {
attach() {
this.count = this.$('.count')
this.inc = this.$('.inc')
this.dec = this.$('.dec')
this.n = 0
this.$on(this.inc, 'click', this.increment)
this.$on(this.dec, 'click', this.decrement)
}
increment() {
this.n++
this.count.textContent = this.n
}
decrement() {
this.n--
this.count.textContent = this.n
}
detach() {
// optional cleanup
}
}
amish.register('counter', Counter)Controller API
this.element- the controller's root elementthis.$(selector)- querySelector scoped to elementthis.$all(selector)- querySelectorAll scoped to elementthis.$on(el, event, handler)- addEventListener with auto-cleanup and boundthisattach()- called when controller is attacheddetach()- called when controller is removed
Run Demo
npm run devOpen http://localhost:5741/examples/
Browser Support
- Chrome/Edge: Full support
- Safari 17.4+: Full support
- Firefox: View transitions behind flag, controllers work everywhere
