# @evolv/mutate

> A library of standard DOM mutations by Evolv AI.

Latest version **2.7.1** (published 2025-12-10) · UNLICENSED license · 0 weekly downloads

## Install

```sh
npm install @evolv/mutate
pnpm add @evolv/mutate
yarn add @evolv/mutate
bun add @evolv/mutate
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.7.1 |
| Published | 2025-12-10 |
| First published | 2022-02-16 |
| Weekly downloads | 0 |
| License | UNLICENSED |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 648.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Evolv Technology Solutions, Inc. |
| Maintainers | matt-strom, robertsevern, evolvengineeringbot, idaunis, emman.mascarinas, samdshermanevolv, charles-evolv |
| Keywords | evolv, mutate, visual editor |

## Links

- npm: https://www.npmjs.com/package/@evolv/mutate
- npm.io page: https://npm.io/package/@evolv/mutate

## Alternatives

- [ext-list](https://npm.io/package/ext-list.md) — 6.3M weekly downloads
- [@lexical/selection](https://npm.io/package/@lexical/selection.md) — 3.8M weekly downloads
- [@lexical/text](https://npm.io/package/@lexical/text.md) — 3.6M weekly downloads
- [@lexical/clipboard](https://npm.io/package/@lexical/clipboard.md) — 3.0M weekly downloads
- [@tiptap/extension-mention](https://npm.io/package/@tiptap/extension-mention.md) — 3.0M weekly downloads

## Recent versions

- 2.7.1 (latest) — 2025-12-10
- 2.7.0 — 2025-12-03
- 2.6.1 — 2025-12-02
- 2.5.1 — 2025-10-30
- 2.4.1 — 2025-07-08
- 2.2.0 — 2025-05-27
- 2.1.8 — 2025-03-14
- 2.1.7 — 2025-03-11
- 2.0.7 — 2025-03-10
- 2.1.5 — 2025-02-21
- 2.1.4 — 2025-02-11
- 2.1.1 — 2025-01-27
- 2.0.6 — 2024-11-22
- 2.0.5 — 2024-10-15
- 2.0.4 — 2024-05-04
- … 54 more at https://npm.io/package/@evolv/mutate/versions

## README

# Mutate

Mutate is a library of helpers to maintain persistent
modifications to the rendered DOM of a web page for
implementation of temporary, experimental changes and
features for rapid experimentation.

It is intended to be framework independent and equally
effective for SPAs and traditionally rendered webpages.

## Getting Set Up

### Installation

```shell
$ npm install @evolv/mutate
```

### Building From Source

Clone the repository and run the following commands.
```shell
$ npm install
$ npm run build
```

### Run Demo Website

There is a demo site included.

*Content warning: flashing lights*

```shell
$ npm run demo
```

## Getting Started

The API for Mutate is similar in a lot of ways to the API of jQuery
with a significant difference, that is selectors (`Collectors`) refer
to all current and future matching `Element`s, and the functions to modify
the DOM (`Mutations`) are persistent.

This means that you don't need to worry about timing, or dynamic areas
of the rendered page.

Mutate also provides the ability to "project" `Element`s of the DOM into
other `Element`s of the DOM, binding all interactions with the "projection"
back to the original `Element`s.

As everyone building variants have learned the hard way, most `Element`s
are dependent on their location in the DOM for both style and functionality.
Projection allows the implementer to "move" and restyle `Element`s without
losing the position dependent functionality of the original `Element`s.

### Importing

```javascript
import {collect, mutate} from '@evolv/mutate';
```

### Basic Usage
The basic flow when using Mutate is to first define a Collector.

```javascript
collect('<selector>', '<collector name>');
```

Then to define a Mutator for the Collector.

```javascript
mutate('<collector name>').hide();
```

Mutators allow for Mutations to be chained together, similar to jQuery which
will be evaluated in order of invocation.

```javascript
mutate('<collector name>').text('<new text value>').classes({'<new class>': true});
```

### Loop Guard (Infinite Loop Protection)

Mutate can detect runaway collectors (e.g. when a mutation keeps creating
elements that re-trigger its own collector) and automatically pause the affected
mutators.

Enable and configure the loop guard at bootstrap time:

```javascript
import { bootstrap } from '@evolv/mutate';

bootstrap({
  loopGuard: {
    enabled: true,
    windowMs: 1000,   // size of the observation window
    threshold: 10,    // max collector events allowed within the window
    cooldownMs: 5000, // time to wait before the same collector can trigger again
    onDetect: (event) => {
      console.warn('Loop detected', event);
    },
  },
});
```

You can also toggle or reconfigure it at runtime through `collect.loopGuard`,
either via the module export or the global `evolv.collect.loopGuard` once
bootstrapped:

```javascript
import { collect } from '@evolv/mutate';

collect.loopGuard.enable({ threshold: 3, windowMs: 500 });
// To disable again:
evolv.collect.loopGuard.disable();
```

Every detection dispatches a `evolv:mutate-loop-detected` `CustomEvent` so host
applications can listen globally:

```javascript
document.addEventListener('evolv:mutate-loop-detected', (event) => {
  console.log('Loop guard tripped', event.detail);
});
```

When the guard trips, the relevant collector is paused, and the active mutators
are paused & reverted so the page remains responsive.

> **Notes**
> - The guard is disabled by default; enable it explicitly and tune `threshold`, `windowMs`, and `cooldownMs` (default `5000ms`) for your scenario. Starting with a higher threshold (default `10` events within `1000ms`) avoids flagging legitimate quick mutations such as `text()` + `styles()`.
> - Built-in effects automatically revert, but custom mutations must provide a `revert` handler if you expect the guard to undo their DOM changes.

#### How to test your changes

1. Run npm start
2. Create a simple website or use codesandbox
3. Add a snippet to head `<script src="http://localhost:8080/index.js"></script>` (make sure that your local is running on 8080, otherwise update src)
4. Apply changes to the website in the console

```javascript
evolv.collect('h1', 'heading')
evolv.mutate('heading').html('Test');
```

## Documentation

[Mutate Documentation](https://evolv-ai.github.io/mutate)

---
_Source: https://npm.io/package/@evolv/mutate · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
