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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stefanobalocco/myopie.js

v2.0.0

Published

View in MVC, but without foresight

Readme

Myopie

French for Myopia

Noun

  • the quality of being short-sighted
  • lack of foresight.

Short-sightedness by design. A client-side lightweight, template-engine-agnostic alternative to Vue for building reactive components, with some code initially ripped from ReefJS.

License GZipped size


Features

  • Component-based rendering — Build dynamic UIs with a minimal API.
  • Two-way data binding — Sync form inputs to state automatically.
  • Efficient DOM diffing — Updates only what changed.
  • Lifecycle hooks — Run custom logic before and after init or render.
  • Template engine agnostic — Works with any function that returns an HTML string.
  • Lightweight — No dependencies. ~2.5kb compressed.

Installation

<script type="module">
import Myopie from 'https://cdn.jsdelivr.net/gh/StefanoBalocco/myopie.js/dist/myopie.min.js';
</script>

Or install the package:

npm add @stefanobalocco/myopie.js
import Myopie from '@stefanobalocco/myopie.js';

Quick Start

<div id="app"></div>
<script type="module">
  import Myopie from 'https://cdn.jsdelivr.net/gh/StefanoBalocco/myopie.js/dist/myopie.min.js';

  const myopie = new Myopie(
    '#app',
    (data) => `<div>
      <input type="text" value="${data.name}" />
      <p>Hello, ${data.name}!</p>
    </div>`,
    { name: 'World' },
    [['input', 'name']]
  );

  myopie.render();

  setTimeout(() => myopie.set('name', 'User'), 2000);
</script>

API

Constructor

new Myopie(selector, template, initialData, inputToPath, timeout, renderOnInput)
  • selector (string) — CSS selector for the root element.
  • template (function) — Function (data) => string that returns the HTML to render.
  • initialData (object, default {}) — Initial state.
  • inputToPath (array, default []) — Input bindings: [selector, path] pairs.
  • timeout (number, default 100) — Debounce delay in milliseconds.
  • renderOnInput (boolean, default true) — Re-render when a bound input changes.

Methods

render()

Renders the DOM immediately. If the template output is unchanged since the previous render, the DOM is not touched. Returns false if the target element is missing, true otherwise.

myopie.render();

renderDebounce()

Schedules a render after the debounce delay. Calls render() directly if timeout is zero.

myopie.renderDebounce();

destroy()

Detaches Myopie-managed event listeners and clears pending render timers. Call this when tearing down the component.

myopie.destroy();

get(path)

Returns the value at path in the current state. Paths are slash-separated and literal / characters are escaped with \. If the final value is a function, Myopie calls it and returns its result.

Path components named __proto__ are blocked to prevent prototype pollution.

const name = myopie.get('name');
const age = myopie.get('user/age');

set(path, value, render = true)

Sets a value at path in the state. Returns true if the value can be set. Triggers a debounced re-render by default.

  • path (string) — Slash-separated path to the property.
  • value (any) — New value.
  • render (boolean, default true) — Trigger a re-render after setting.
myopie.set('name', 'World');
myopie.set('user/age', 30);

del(path, render = true)

Deletes a value at path in the state. Returns true if it deletes a value. Triggers a debounced re-render by default.

  • path (string) — Slash-separated path to the value.
  • render (boolean, default true) — Trigger a re-render after deletion.
myopie.del('name');
myopie.del('user/age');
myopie.del('items/2');

handlersPermanentAdd(selector, event, listener)

Registers a persistent event listener for elements matching selector. The listener survives re-renders. Returns false if an identical listener is already registered.

const handler = (e) => myopie.set('name', 'Foo');
myopie.handlersPermanentAdd('input[name="foo"]', 'click', handler);

handlersPermanentDel(selector, event?, listener?)

Removes persistent listeners for selector. Pass event to remove only matching events; pass listener to remove a specific function. Omit both to clear all listeners for that selector.

myopie.handlersPermanentDel('input[name="foo"]', 'click', handler); // remove one listener
myopie.handlersPermanentDel('input[name="foo"]', 'click');          // remove by event
myopie.handlersPermanentDel('input[name="foo"]');                   // remove all

Lifecycle Hooks

Hooks run at specific points during initialization and rendering.

  • hooksInitAddPre(fn) — Before first render. Receives (dataCurrent).
  • hooksInitAddPost(fn) — After first render. Receives (dataCurrent).
  • hooksRenderAddPre(fn) — Before each subsequent render. Receives (dataCurrent, dataPrevious).
  • hooksRenderAddPost(fn) — After each subsequent render. Receives (dataCurrent, dataPrevious).
myopie.hooksInitAddPre((data) => {
  console.log('Before first render', data);
});

myopie.hooksRenderAddPost((current, previous) => {
  console.log('Rendered. Previous state:', previous);
});

data-myopie-* Attributes

Add these attributes to elements in your template to guide the DOM diffing algorithm. Myopie strips data-myopie-default-* and data-myopie-ignore-* attributes from the live DOM after each render.

data-myopie-id

Assigns a stable identity to an element. During diffing, sibling elements with the same data-myopie-id value match each other regardless of their position among siblings.

<li data-myopie-id="item-42">...</li>

data-myopie-ignore-content

Prevents the diffing algorithm from overwriting the element's inner content (and that of its descendants). Use this for elements managed by third-party libraries.

<div data-myopie-ignore-content="true"><!-- managed externally --></div>

data-myopie-ignore-style

Prevents the diffing algorithm from overwriting the style attribute on the element and its descendants. Use this when inline styles are set dynamically, for example by an animation library.

<div data-myopie-ignore-style="true" style="transform: translateX(100px)">...</div>

data-myopie-default-*

Sets an attribute only when that attribute is absent from the live element. The attribute name follows the prefix: data-myopie-default-placeholder sets placeholder.

Adds the target attribute only when absent; otherwise, normal reconciliation removes it unless the template also includes the real attribute.

<input data-myopie-default-placeholder="Type here…" />

Contributing

Open an issue or submit a pull request on GitHub.


License

Released under the BSD-3-Clause License.