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

undo-anything

v0.1.0

Published

Universal Ctrl+Z for any web action. Zero dependency, < 3kb gzip.

Downloads

180

Readme

undo-anything.js

Universal Ctrl+Z for any web action. DOM mutations, inputs, custom actions. Zero dependency, < 3kb gzip.

npm version license gzip size

The problem: Users accidentally delete items, change values, or trigger actions they didn't mean to — and there's no way back.

The solution: 2 lines of code.


Install

npm install undo-anything

Or via CDN:

<script type="module">
  import Undo from 'https://cdn.jsdelivr.net/npm/undo-anything/src/undo-anything.js'
</script>

Quick start

import Undo from 'undo-anything'

// Watch a container — all DOM changes become undoable
Undo.watch('#my-list')

// Now Ctrl+Z restores deleted items, Ctrl+Y re-deletes them

Options

Undo.watch('#my-list', {
  maxHistory: 50,          // max actions stored (default: 50)
  shortcut:   true,        // enable Ctrl+Z / Ctrl+Y (default: true)
  toast:      true,        // show "Action undone — Redo?" toast (default: true)
  onUndo: (action) => {},  // callback after undo
  onRedo: (action) => {},  // callback after redo
})

Custom actions

For anything beyond DOM mutations, use Undo.push():

// Example: custom counter
let count = 0

document.getElementById('increment').addEventListener('click', () => {
  const prev = count
  count++
  updateUI()

  Undo.push({
    label: `Increment ${prev} → ${count}`,
    undo: () => { count = prev; updateUI() },
    redo: () => { count++; updateUI() }
  })
})

// Now Ctrl+Z decrements the counter

Methods

// Manual undo / redo
Undo.undo()
Undo.redo()

// Push a custom undoable action
Undo.push({ label: 'My action', undo: () => {}, redo: () => {} })

// Stop watching a container
Undo.unwatch('#my-list')

// Clear history
Undo.clear()

// Inspect the stacks
Undo.history()
// → { undo: [...actions], redo: [...actions] }

What gets tracked automatically

| Action | Tracked | |---|---| | Element removed from DOM | ✅ restored at exact position | | Element added to DOM | ✅ removed on undo | | Attribute changed (class, style, data-*) | ✅ reverted | | Input / textarea blur | ✅ value reverted | | Custom action via push() | ✅ anything you define |


Keyboard shortcuts

| Shortcut | Action | |---|---| | Ctrl+Z / Cmd+Z | Undo last action | | Ctrl+Y / Ctrl+Shift+Z | Redo last undone action |

Shortcuts are disabled when focus is inside an <input> or <textarea> to preserve native browser behavior.


Framework usage

React

import Undo from 'undo-anything'
import { useEffect } from 'react'

function TaskList() {
  useEffect(() => {
    Undo.watch('#task-list', { toast: true })
    return () => Undo.unwatch('#task-list')
  }, [])

  return <ul id="task-list">...</ul>
}

Vue

<script setup>
import Undo from 'undo-anything'
import { onMounted, onUnmounted } from 'vue'

onMounted(() => Undo.watch('#list'))
onUnmounted(() => Undo.unwatch('#list'))
</script>

Browser support

| Chrome | Firefox | Safari | Edge | |---|---|---|---| | ✅ 64+ | ✅ 63+ | ✅ 11.1+ | ✅ 79+ |

Requires MutationObserver and BroadcastChannel — available in all modern browsers.


License

MIT © TwinMi Studio