I’d like to share a library of mine that I’ve been using in production for quite some time now:
Very Simple Components – When even Alpinejs or Petite-Vue would be too much
What it does is simply provide a convenient way to attach JavaScript/TypeScript to the DOM. It takes some of the verbosity out of vanilla JS, and keeps everything organized as components.
An example: You want a simple gallery component with slides and prev/next buttons
// components/gallery.js
import { registerComponent, defineOptions } from '@very-simple/components'
const options = defineOptions({
props: { loop: Boolean }
})
registerComponent('gallery', options, ({ el, props, refs, refsAll }) => {
// Props are read from el's dataset and are automatically converted to the correct
// type. Default values are also possible, see documentation.
const { loop } = props
// Multiple HTML elements can have the same `ref` name. They will be
// grouped in `refsAll` ...
const { slides } = refsAll
// ... whereas `refs` only stores a single element per name.
const { prev, next } = refs
let currentIndex = 0
const maxIndex = slides.length - 1
const selectSlide = index => {
if (!loop && (index < 0 || index > maxIndex)) return
currentIndex = index < 0 ? maxIndex : index > maxIndex ? 0 : index
slides.forEach((el, index) => (el.hidden = index !== currentIndex))
}
// Add event listeners.
prev.addEventListener('click', () => selectSlide(currentIndex - 1))
next.addEventListener('click', () => selectSlide(currentIndex + 1))
// Show the first slide.
selectSlide(currentIndex)
})
<!-- template.php -->
<!-- For better reusability this would go into a snippet -->
<div data-simple-component="gallery" data-loop="true">
<div data-ref="slides">A</div>
<div data-ref="slides">B</div>
<div data-ref="slides">C</div>
<button data-ref="prev">Prev</button>
<button data-ref="next">Next</button>
</div>
<script type="module">
import { mountComponents } from '@very-simple/components'
// We only have to import the component, it will register itself.
import './components/gallery.js'
// This will look for any elements with a `data-simple-component` attribute and
// mount the corresponding component.
mountComponents()
</script>
So there’s not a lot of magic here, and no reactivity like in most other frontend frameworks. It’s just some helpers and quality-of-life features that make working with vanilla JS a little nicer. And it is super small, less than 1kb (minify and gzip)!
It provides some additional features not shown in the example, like fully typed native component events and exposing methods on a component’s HTML element (e.g: myMenu.$component.open()
).
Also you get great auto-completion in your IDE and strict type checking when using TypeScript. The library hasn’t reached 1.0.0
yet, so things may change, but it’s already production-ready.