# https://github.com/NeXTs/Jets.js Project Manual

Generated at: 2026-06-27 19:21:39 UTC

## Table of Contents

- [Overview and Getting Started](#page-overview)
- [Configuration and API Reference](#page-api)
- [Architecture and Internal Data Flow](#page-architecture)
- [Advanced Usage, Community Patterns and Troubleshooting](#page-advanced)

<a id='page-overview'></a>

## Overview and Getting Started

### Related Pages

Related topics: [Configuration and API Reference](#page-api), [Architecture and Internal Data Flow](#page-architecture)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md)
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json)
- [bower.json](https://github.com/NeXTs/Jets.js/blob/main/bower.json)
- [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js)
- [jets.min.js](https://github.com/NeXTs/Jets.js/blob/main/jets.min.js)
</details>

# Overview and Getting Started

## What is Jets.js?

Jets.js is a client-side, dependency-free search library that turns any HTML list into a fast, filterable list by leveraging the browser's native CSS engine. Rather than iterating over DOM nodes in JavaScript on every keystroke, Jets.js writes a single dynamic `<style>` rule into the document `<head>` and lets the browser do the work via the `:not([data-jets~="…"])` attribute selector. Source: [README.md:1-12](https://github.com/NeXTs/Jets.js/blob/main/README.md).

The project is a small, single-file library. The unminified source [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js) is roughly 150 lines of JavaScript wrapped in a UMD shim, and a minified build is shipped as [jets.min.js](https://github.com/NeXTs/Jets.js/blob/main/jets.min.js). Both files export a global `Jets` constructor on `window`, an AMD module via `define`, and a CommonJS module via `module.exports` (see [bower.json:5-9](https://github.com/NeXTs/Jets.js/blob/main/bower.json) and [package.json:3-7](https://github.com/NeXTs/Jets.js/blob/main/package.json)).

## Installation

Three install paths are supported out of the box:

- **npm** — `npm install jets`. The `main` entry is `jets.js` ([package.json:3-7](https://github.com/NeXTs/Jets.js/blob/main/package.json)).
- **Bower** — `bower install jets`. The `main` entry is `jets.min.js` ([bower.json:1-9](https://github.com/NeXTs/Jets.js/blob/main/bower.json)).
- **Direct `<script>` include** — drop `jets.min.js` into a page; it will expose `window.Jets` thanks to the UMD wrapper at the top of [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js).

The published version is `0.15.0` and the project license is MIT ([package.json:2,17](https://github.com/NeXTs/Jets.js/blob/main/package.json)).

## Quick Start

A minimal integration needs three things: a search input, a container, and a list of items. Jets.js annotates each item with a `data-jets` attribute that holds a sanitized (lowercased, diacritic-stripped, whitespace-collapsed) copy of its searchable text, then writes a CSS rule that hides any item whose attribute does not contain the current search term. Source: [jets.js:90-130](https://github.com/NeXTs/Jets.js/blob/main/jets.js).

```html
<input type="text" id="search" />
<ul id="content">
  <li>Apples</li>
  <li>Oranges</li>
  <li>Bananas</li>
</ul>

<script src="jets.min.js"></script>
<script>
  new Jets({
    searchTag: '#search',
    contentTag: '#content'
  });
</script>
```

The constructor attaches `input`, `keydown`, and `change` listeners to `searchTag` and rebuilds the CSS rule on every change ([jets.js:60-80](https://github.com/NeXTs/Jets.js/blob/main/jets.js)). If you would rather drive searches yourself, pass `callSearchManually: true` and call `instance.search('phrase')` from your own code path ([jets.js:30-45](https://github.com/NeXTs/Jets.js/blob/main/jets.js)).

## How It Works

The runtime is intentionally simple. On construction Jets.js creates a `<style>` element (with an optional `nonce` for CSP-strict environments), walks every direct child of `contentTag`, and stores a sanitized version of each child's text in its `data-jets` attribute. On every search event it rebuilds one CSS rule of the shape `#content > :not([data-jets~="foo"]) { display:none }` and assigns it to the `<style>` tag's `innerHTML`. Source: [jets.js:55-130](https://github.com/NeXTs/Jets.js/blob/main/jets.js).

```mermaid
flowchart LR
  A["User types in searchTag"] --> B["_onSearch handler<br/>(input/keydown/change)"]
  B --> C["Sanitize query<br/>trim, lowercase, replace diacritics"]
  C --> D["Build CSS selector<br/>#content > :not([data-jets~=…])"]
  D --> E["styleTag.innerHTML = rule"]
  E --> F["Browser applies<br/>CSS to hide non-matches"]
  H["constructor"] --> I["_setJets: write data-jets<br/>on each direct child"]
  I --> J["_addStyleTag: inject &lt;style&gt;"]
  J --> B
```

A `:scope` polyfill is bundled so the library works in older browsers that lack `:scope > *` ([jets.js:140-160](https://github.com/NeXTs/Jets.js/blob/main/jets.js)). To reflect DOM changes after construction, call `instance.update(force)` to re-scan new or modified items; passing `force: true` rewrites `data-jets` on every child ([jets.js:125-140](https://github.com/NeXTs/Jets.js/blob/main/jets.js)).

## Core Configuration Options

The options object is shallow-merged with internal defaults inside the constructor. Source: [jets.js:18-35](https://github.com/NeXTs/Jets.js/blob/main/jets.js).

| Option | Type | Default | Purpose |
|---|---|---|---|
| `searchTag` | string (selector) | — | Element bound to `input`/`keydown`/`change` events. |
| `contentTag` | string (selector) | — | Container whose direct children become searchable. |
| `searchSelector` | string | `'*AND'` | First char is the attribute operator (`*`, `^`, `$`, `~`); remainder is the match mode (`AND` or `OR`). |
| `hideBy` | string | `'display:none'` | CSS declarations appended to each hide rule. |
| `addImportant` | boolean | `false` | Appends `!important` to every `hideBy` declaration. |
| `columns` | number[] | — | Restrict searchable text to specific child indices of each row. |
| `manualContentHandling` | function | — | Returns custom text for a row instead of reading `textContent`. |
| `callSearchManually` | boolean | `false` | Disables automatic event listeners; you call `.search(phrase)`. |
| `invert` | boolean | `false` | Matches items *without* the term instead of *with* it. |
| `didSearch` | function | — | Callback fired with the new query after each search. |
| `nonceId` | string | — | Sets the CSP `nonce` attribute on the injected `<style>` tag. |
| `diacriticsMap` | object | `{}` | Map of ASCII letter → array of diacritic variants to strip. |
| `searchInSpecificColumn` | boolean | `false` | Also writes per-column `data-jets-col-N` attributes. |

## Known Issues and Community Workarounds

A few recurring questions are worth highlighting for new users:

- **"Nothing found" feedback.** Jets.js only toggles visibility — it does not detect an empty result set. To show a custom "no matches" message, listen to the `didSearch` option and inspect how many rows remain visible after the CSS rule applies. Community discussion: issue #39.
- **Custom attribute name.** The library hard-codes `data-jets` and `data-jets-col-N`. There is no built-in option to rename the attribute, so reuse of that attribute for other purposes (issue #40) can cause conflicts.
- **CSP / inline styles.** Because the library writes to `styleTag.innerHTML`, strict `style-src` policies will block it. The supported mitigation is to pass `nonceId` matching your policy's nonce; without that, you must allow `'unsafe-inline'`. Community discussion: issue #44. The implementation lives in `_addStyleTag` ([jets.js:65-72](https://github.com/NeXTs/Jets.js/blob/main/jets.js)).
- **CI status.** The Travis badge in [README.md:3](https://github.com/NeXTs/Jets.js/blob/main/README.md) refers to an external CI that has had intermittent failures (issue #43); the local `npm test` script uses `mocha-headless-chrome` against `test/index.html` ([package.json:8](https://github.com/NeXTs/Jets.js/blob/main/package.json)).

## See Also

- [Configuration Options Reference](#) — full table of options including column-based search.
- [Public API: `search`, `update`, `destroy`](#) — programmatic control after construction.
- [CSP and Security Notes](#) — detailed guidance on `nonceId` and strict policies.
- [Architecture and Internals](#) — deep dive into the `_applyCSS` and `_setJets` flows.

---

<a id='page-api'></a>

## Configuration and API Reference

### Related Pages

Related topics: [Overview and Getting Started](#page-overview), [Architecture and Internal Data Flow](#page-architecture), [Advanced Usage, Community Patterns and Troubleshooting](#page-advanced)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js)
- [jets.min.js](https://github.com/NeXTs/Jets.js/blob/main/jets.min.js)
- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md)
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json)
- [bower.json](https://github.com/NeXTs/Jets.js/blob/main/bower.json)
</details>

# Configuration and API Reference

This page documents the public configuration options accepted by the `Jets` constructor and the public/protected methods exposed on the `Jets` prototype in version `0.15.0`. All references in this document map to the unminified source so that line-anchored citations remain stable. Source: [package.json:3]() and [jets.js:1-2]()

## Overview of the Public Surface

Jets.js is delivered as a single-file, dependency-free UMD module. The `Jets` constructor can be called with or without `new`; when invoked without `new` it re-enters via `new Jets(opts)` to keep instantiation safe. Source: [jets.js:10-12]()

The module registers itself through a UMD wrapper that supports CommonJS, AMD, and a browser global. Source: [jets.js:4-8]() and [jets.min.js:5-7]() The build artifact referenced by package managers is `jets.js` (unminified) per `package.json`, while `bower.json` points to `jets.min.js`. Source: [package.json:5]() and [bower.json:3]()

The constructor takes a single `opts` object. Two selectors are required for the typical (non-manual) usage: `contentTag` and `searchTag`. If `contentTag` resolves to no elements, the constructor throws. Source: [jets.js:30-32]() If neither `searchTag` nor `callSearchManually: true` is supplied, it also throws, forcing the caller to pick a search mode. Source: [jets.js:33-34]()

## Configuration Options

The defaults object supplies three baseline values; every other key is read from `opts` and falls back to `undefined` when not provided. Source: [jets.js:14-18]() and [jets.js:19-22]()

| Option | Type | Default | Purpose |
| --- | --- | --- | --- |
| `contentTag` | string (CSS selector) | — (required) | Container whose direct children are searchable items. Source: [jets.js:30-31]() |
| `searchTag` | string (CSS selector) | — (required unless `callSearchManually`) | Input element that drives the query. Source: [jets.js:32-33]() |
| `searchSelector` | string | `'*AND'` | First char is the attribute operator (`*`, `^`, `$`, `~`); remainder is the boolean mode (`AND`, `OR`). Source: [jets.js:22-26]() |
| `hideBy` | string | `'display:none'` | CSS declarations applied to non-matching items. Multiple rules may be separated with `;`. Source: [jets.js:15]() and [jets.js:108-110]() |
| `addImportant` | boolean | `undefined` | Appends `!important` to each rule in `hideBy`. Source: [jets.js:108-110]() |
| `columns` | number[] | `undefined` | Restrict indexing to specific child indices of each row. Source: [jets.js:144-150]() |
| `manualContentHandling` | function | `undefined` | Caller-supplied function returning the text used to index a tag. Source: [jets.js:142-144]() |
| `callSearchManually` | boolean | `undefined` | Disables auto event binding; search must be triggered via `.search(phrase)`. Source: [jets.js:33-34]() and [jets.js:36-39]() |
| `searchInSpecificColumn` | boolean | `undefined` | Enables per-column `data-jets-col-N` attributes. Source: [jets.js:130-138]() |
| `diacriticsMap` | object | `{}` | Map of ASCII letter → array of diacritic variants to fold during sanitization. Source: [jets.js:16-17]() and [jets.js:154-162]() |
| `didSearch` | function | `undefined` | Callback invoked with the last applied query. Source: [jets.js:43-44]() |
| `invert` | boolean | `undefined` | When true, hides matches instead of non-matches. Source: [jets.js:104-106]() |
| `nonceId` | string | `undefined` | CSP nonce written onto the injected `<style>` element. Source: [jets.js:113-115]() |

The `searchSelector` string is split: position 0 becomes the attribute operator and the remainder (uppercased) becomes `searchSelectorMode`. A mode of `AND` produces comma-joined descendant selectors and disables duplicate word filtering. Source: [jets.js:23-26]() and [jets.js:98-103]()

### CSP and the `nonceId` Option

Because Jets injects a `<style>` element into `document.head` and writes its `innerHTML` on every keystroke, it can violate strict Content Security Policies. The `nonceId` option is the supported workaround: when provided, it is applied via `setAttribute('nonce', options.nonceId)` on the style tag. Source: [jets.js:112-115]() and [jets.js:117]() This directly addresses the community-reported CSP violation in issue #44, which the simple `style-src 'unsafe-inline'` allowance would otherwise be required to bypass.

## Public API

### `new Jets(opts)` / `Jets(opts)`

Constructor. Initializes the index, attaches event listeners (unless `callSearchManually`), injects the style tag, and applies an initial empty query so the document reflects the post-init state. Source: [jets.js:30-52]()

### `jets.search(query?, columnIndex?)`

Performs a search. When `callSearchManually` is `true`, the first argument is used verbatim; otherwise the current value of the bound input is read. The second optional argument restricts matching to a single column index (requires `searchInSpecificColumn`). The method short-circuits when the new query equals the last applied query, preventing redundant DOM writes. Source: [jets.js:36-44]() and [jets.js:95-111]()

### `jets.update(force?)`

Re-indexes rows that have not yet been stamped with a `data-jets` attribute; passing `force = true` re-indexes every row. Use this after dynamically inserting items into `contentTag`. Source: [jets.js:164-166]()

### `jets.destroy()`

Removes event listeners (when they were auto-attached), deletes the injected style tag, and clears `data-jets` / `data-jets-col-*` attributes. Source: [jets.js:46-50]() and [jets.js:167-172]()

### `jets.replaceDiacritics(text)`

Public helper that applies the configured `diacriticsMap` to a string and returns the result. Source: [jets.js:154-162]()

## Internals Relevant to Configuration

`_applyCSS(query, column)` is the engine that turns a query into a CSS rule. It lowercases, trims, collapses whitespace, escapes backslashes, and — when `searchSelectorMode` is set — splits on spaces, deduplicating tokens. Source: [jets.js:97-103]() Each token becomes an attribute selector using the configured operator (e.g. `*=` for the default `'*AND'`), wrapped in `:not(...)` unless `invert` is true. Source: [jets.js:104-107]()

The `nonceId` only helps CSP when the host page also lists that nonce in its `style-src` directive. Without it, the issue described in #44 requires `'unsafe-inline'` or a hash-based allowance. Source: [jets.js:113-115]()

For case-insensitive matching (issue #40), the `[attr="value"]` selector used by Jets is already case-sensitive in HTML; the workaround is to lowercase the indexed text via the `data-jets` attribute, which the source does in `_sanitize`. Source: [jets.js:120-122]()

A `didSearch` callback is the recommended extension point for implementing a "no results" message (issue #39): the caller can count visible items in the handler and render a placeholder element accordingly. Source: [jets.js:43-44]()

The community-contributed `attrName` idea (issue #18) is not part of the current public API; multi-instance differentiation is achieved by giving each instance its own `contentTag` / `searchTag` pair.

## See Also

- Project home: [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md)
- NPM package metadata: [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json)
- Bower package metadata: [bower.json](https://github.com/NeXTs/Jets.js/blob/main/bower.json)
- Issue #39 — "Display message 'nothing found'?"
- Issue #18 — "Add custom attrName"
- Issue #44 — "CSP violation"
- Issue #40 — "Search term should be case insensitive"

---

<a id='page-architecture'></a>

## Architecture and Internal Data Flow

### Related Pages

Related topics: [Configuration and API Reference](#page-api), [Advanced Usage, Community Patterns and Troubleshooting](#page-advanced)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js)
- [jets.min.js](https://github.com/NeXTs/Jets.js/blob/main/jets.min.js)
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json)
- [bower.json](https://github.com/NeXTs/Jets.js/blob/main/bower.json)
- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md)

</details>

# Architecture and Internal Data Flow

## Overview

Jets.js is a "Native CSS search engine" that performs client-side filtering on lists by generating dynamic CSS attribute selectors rather than manipulating the DOM imperatively. At version `0.15.0` (released 2022-12-11), the entire library ships as a single-file UMD module with no external runtime dependencies, integrating with a search input element via native DOM events. Source: [package.json:3-6](), [README.md:1-5]().

The library's elegance lies in a small, well-defined pipeline: scrape text once, sanitize it, stamp it onto DOM elements as an HTML attribute, and let the browser's CSS engine perform the matching work via a single attribute-selector rule written into a `<style>` block.

## Module Loading & Public Surface

Jets.js exposes itself through a UMD wrapper, so the same file works under CommonJS (`module.exports`), AMD (`define`), and browser-global (`window.Jets`) environments. Source: [jets.js:6-10](). The Bower manifest advertises `jets.min.js` as the entry point while the npm manifest points to `jets.js`. Source: [bower.json:3](), [package.json:4]().

The constructor accepts an options object and returns a `Jets` instance even when called without `new`, thanks to a self-instantiation guard at the top of the function body. Source: [jets.js:13-15](). The minified build preserves the same shape; the public surface is the single `Jets` function. Source: [jets.min.js:1-3]().

## Internal State & Configuration

The constructor builds an `options` object by merging user-supplied keys with defaults. The recognized keys are: `columns, addImportant, searchSelector, hideBy, manualContentHandling, callSearchManually, searchInSpecificColumn, diacriticsMap, didSearch, invert, nonceId`. Defaults are `{ searchSelector: '*AND', hideBy: 'display:none', diacriticsMap: {} }`. Source: [jets.js:17-26]().

A notable parsing step splits `searchSelector` when it is longer than one character: the first character becomes the CSS attribute operator (`*`, `^`, `$`, `~`, and so on) and the remainder becomes the boolean combination mode (`AND`, `OR`, etc.). Source: [jets.js:27-30](). This dual encoding is what allows the use case described in community issue #18 ("Add custom attrName" — multiple Jets instances against the same element) to be expressed through the same option.

Three DOM references are captured at construction time:

- `self.content_tag` — `querySelectorAll(opts.contentTag)` result, the list container(s).
- `self.search_tag` — `querySelector(opts.searchTag)` result, the input field.
- `self.content_param` — the original selector string, re-used later when composing descendant selectors. Source: [jets.js:31-35]().

The constructor throws a descriptive `Error` if `contentTag` cannot be found, or if neither `searchTag` nor `callSearchManually` is provided. Source: [jets.js:32-35]().

## The Data Flow Pipeline

The runtime behavior of Jets.js follows a strictly ordered pipeline that runs once during construction and again on every search event. The diagram below captures this data flow end-to-end.

```mermaid
flowchart LR
    A[DOM content tags] -->|_setJets| B[data-jets attribute]
    B -->|_applyCSS| C[CSS selector rule]
    C -->|<style> innerHTML| D[Browser hides non-matches]
    E[User keystroke] -->|_onSearch| F[self.search]
    F -->|replaceDiacritics<br/>+ _sanitize| C
    F -. didSearch callback .-> G[Consumer code]
```

**Step 1 — Indexing (`_setJets`).** The method walks each `content_tag` descendant and writes a sanitized version of its text into the `data-jets` attribute. Sanitization removes diacritics via the user-provided `diacriticsMap`, collapses whitespace with `\s+`, trims, and lowercases the result. Source: [jets.js:_setJets](), [jets.js:_sanitize](). For column-restricted searches, only the children at the configured `columns` indices contribute to the indexed text, joined with a single space. Source: [jets.js:_setJets]().

**Step 2 — Style injection (`_addStyleTag`).** A `<style>` element is appended to `document.head`. If `nonceId` is supplied in the options, it is set as the `nonce` attribute — the supported escape hatch for strict Content-Security-Policy environments. Source: [jets.js:_addStyleTag](). This addresses the CSP violation reported in community issue #44: without a nonce, the inline style block is rejected by browsers enforcing `style-src` without `'unsafe-inline'`.

**Step 3 — Search (`_applyCSS`).** When the user types, `_onSearch` debounces a `setTimeout(0)` for `keydown` and fires synchronously for `input` and `change`. Source: [jets.js:_onSearch](). The query is normalized, optionally split into deduplicated words for multi-word modes, and assembled into a selector such as `container > :not([data-jets*="word1"]):not([data-jets*="word2"])` (or its inverse when `invert: true`). Source: [jets.js:_applyCSS](). The rule is written to `this.styleTag.innerHTML`, and the browser does the rest.

**Step 4 — Notification (`didSearch`).** After the CSS is applied, the optional `didSearch` callback fires with the normalized query string. Source: [jets.js:43-50](). This is the recommended hook for the "nothing found" message requested in community issue #39 — subscribe and count visible items (or just observe an empty result) to render a placeholder.

## Lifecycle, Updates & Teardown

Three public methods round out the API and live on `Jets.prototype`:

- `update(force)` — re-indexes any newly inserted rows that lack a `data-jets` attribute; passing `force=true` re-indexes every descendant. Source: [jets.js:update]().
- `search(query, column)` — programmatic invocation, used when `callSearchManually: true` is set. Source: [jets.js:42-50]().
- `destroy()` — detaches event listeners (unless in manual mode), removes the `<style>` tag from `document.head`, and strips every `data-jets*` attribute the instance wrote. Source: [jets.js:_destroy](), [jets.js:destroy]().

A short-circuit at the start of `search` skips re-application when the normalized query has not changed since the last call, preventing redundant DOM work on no-op keystrokes. Source: [jets.js:42-50]().

## Common Failure Modes & Community Notes

- **CSP violation (issue #44).** The injected `<style>` block is inline and may be blocked under strict `style-src` policies. Pass `nonceId` to the constructor and ensure your policy mirrors that nonce. Source: [jets.js:_addStyleTag]().
- **"Nothing found" placeholder (issue #39).** Jets.js intentionally ships with no built-in empty-state UI. Use the `didSearch` callback to render your own message based on the current query. Source: [jets.js:43-50]().
- **Case-insensitive matching (issue #40).** `_sanitize` always lowercases the indexed text, and `_applyCSS` also lowercases the query before generating the selector, so matching is case-insensitive by design. Source: [jets.js:_sanitize](), [jets.js:_applyCSS]().
- **Multiple instances on one element (issue #18).** Distinct attribute names per instance can be achieved by varying the leading operator character of `searchSelector`, allowing several Jets engines to coexist against overlapping content. Source: [jets.js:27-30]().
- **Travis CI failure (issue #43).** The npm script is `mocha-headless-chrome -f ./test/index.html`; CI failures are environmental and unrelated to the runtime architecture. Source: [package.json:7-9]().

## See Also

- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md) — Project overview and usage example.
- [Project homepage](https://jets.js.org/) — Live demo referenced from the README banner.
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json) — Version metadata and test command.

---

<a id='page-advanced'></a>

## Advanced Usage, Community Patterns and Troubleshooting

### Related Pages

Related topics: [Configuration and API Reference](#page-api), [Architecture and Internal Data Flow](#page-architecture)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [jets.js](https://github.com/NeXTs/Jets.js/blob/main/jets.js)
- [jets.min.js](https://github.com/NeXTs/Jets.js/blob/main/jets.min.js)
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json)
- [bower.json](https://github.com/NeXTs/Jets.js/blob/main/bower.json)
- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md)
</details>

# Advanced Usage, Community Patterns and Troubleshooting

This page documents non‑trivial usage patterns, configuration options and community‑reported workarounds for the Jets.js library (a "native CSS search engine"). It focuses on topics that go beyond the basic `searchTag` / `contentTag` examples in the README, drawing directly from the implementation in `jets.js` and the issues most commonly raised by users.

## Overview of the Public API

The whole library is exposed as a single constructor: `new Jets(opts)`. All options are read from the `opts` argument and merged against `defaults` (`searchSelector: '*AND'`, `hideBy: 'display:none'`, `diacriticsMap: {}`) inside the constructor.

Source: [jets.js:7-15]()

The accepted option keys are explicitly enumerated:

```js
['columns', 'addImportant', 'searchSelector', 'hideBy',
 'manualContentHandling', 'callSearchManually',
 'searchInSpecificColumn', 'diacriticsMap',
 'didSearch', 'invert', 'nonceId']
```

Source: [jets.js:16-18]()

Notable instance methods exposed on `self` include `search(query, optional_column)`, `update(force)`, `destroy()`, and `replaceDiacritics(text)`. The `search` function short‑circuits when the query has not changed, which makes manual invocation cheap.

Source: [jets.js:41-50]()

## Advanced Configuration Patterns

### Multiple search words (AND / OR modes)

`searchSelector` is parsed as a single character plus a mode string. If it is longer than one character (e.g. `*AND`, `+OR`), the first character becomes the attribute selector operator and the rest becomes the `searchSelectorMode`.

Source: [jets.js:19-22]()

When `searchSelectorMode === 'AND'`, the query is split on spaces, deduplicated, and every token must match the corresponding `data-jets*="..."` attribute. This is how the default `*AND` selector enforces multi‑word filtering.

Source: [jets.js:115-126]()

### Per‑column and custom content extraction

`columns` restricts the text used to build the searchable `data-jets` value to specific child indices, while `manualContentHandling` lets callers fully override how text is extracted from a tag.

Source: [jets.js:170-183]()

`searchInSpecificColumn` combined with `_handleSpecificColumns` writes a sibling attribute `data-jets-col-<i>` per row, which the CSS generator can target via the optional second argument to `search(query, column)`.

Source: [jets.js:155-168]()

### Inverted and forced hiding

Setting `invert: true` flips the generated selector from `:not([data-jets*="..."])` to a plain `[data-jets*="..."]` rule, so that the matching rows are hidden instead of the non‑matching ones. `addImportant` appends `!important` to every rule in `hideBy`.

Source: [jets.js:116-122]()

### Diacritic and case normalization

Both the indexed text and the live query are normalized through `_sanitize`, which calls `replaceDiacritics`, collapses whitespace, trims, and lowercases:

```js
return this.replaceDiacritics(text).trim().replace(/\s+/g, ' ').toLowerCase()
```

Source: [jets.js:142-144]()

This addresses the case‑sensitivity concern raised in community issue #40 — Jets.js is case insensitive out of the box, but consumers cannot reuse `data-jets` for other purposes because the attribute is owned by the library.

### Manual search triggering

When `callSearchManually: true` is set, the constructor does not bind `input`, `keydown`, or `change` listeners; instead, the consumer must call `jets.search("phrase")` themselves. This is required if there is no `searchTag` element.

Source: [jets.js:52-58]()

## Lifecycle: update and destroy

`update(force)` walks the content tree and indexes any element that is missing the `data-jets` attribute (or all of them when `force === true`). This is the documented way to keep the index in sync after adding rows to the DOM.

Source: [jets.js:201-203]()

`destroy()` removes the injected `<style>` element, strips `data-jets` and `data-jets-col-*` attributes from every indexed tag, and detaches event listeners (unless `callSearchManually` was used).

Source: [jets.js:55-57](), [jets.js:204-210]()

## Community Workarounds and Troubleshooting

### "Nothing found" message (issue #39)

The library does not render any empty‑state markup on its own — when no rows match, the `data-jets*="..."` selector simply hides every row, leaving a blank list. The official escape hatch is the `didSearch` callback, which fires after every successful query change:

```js
new Jets({
  contentTag: '#list',
  searchTag:  '#search',
  didSearch: function (query) {
    var visible = document.querySelectorAll(
      '#list > :not([data-jets]):not([data-jets*=""])'
    );
    document.querySelector('#empty').style.display =
      visible.length ? 'none' : 'block';
  }
});
```

Source: [jets.js:48-50]()

### CSP violations (issue #44)

Jets.js injectates a `<style>` tag into `document.head` and writes its `innerHTML` on every keystroke. Browsers enforcing a strict `style-src` policy will block this injection. Two mitigations are baked into the library:

1. Pass `nonceId` in the options — the constructor sets that nonce on the dynamically created `<style>` element.
   Source: [jets.js:130-134]()
2. Serve the library itself from an origin allowed by your `script-src` directive (the file is published as a single global, AMD module, and CommonJS module).
   Source: [package.json:1-7](), [bower.json:1-6]()

There is no option to disable the `<style>` tag entirely; removing it would defeat the "native CSS" approach.

### Custom attribute name (issue #18)

The `data-jets` attribute name is hard‑coded throughout the implementation (it is referenced in `_setJets`, `_applyCSS`, `_destroy`, and `_getContentTags`). The library does not expose an `attrName` option, so the canonical workaround for users who need a different attribute (or multiple Jets instances on the same elements) is to fork `jets.js` and rename the literal strings — there is no runtime configuration that achieves this.

Source: [jets.js:170-185](), [jets.js:115-126]()

### Trailing CI status (issue #43)

Travis CI has been the project's continuous integration provider since the earliest releases. The `npm test` script invokes `mocha-headless-chrome` against `test/index.html`, so contributors reproducing a local failure should run the same command with a recent headless Chrome.

Source: [package.json:6-8](), [README.md:3-3]()

## Summary

| Concern | Library support | Workaround |
|---|---|---|
| Empty results UI | None built‑in | `didSearch` callback |
| CSP `style-src` | `nonceId` option | Add nonce, whitelist CDN |
| Custom attribute | Not supported | Fork & rename |
| Case sensitivity | Already lowercased | `_sanitize` |
| Dynamic content | `update(force)` | Call after DOM mutation |

## See Also

- [README.md](https://github.com/NeXTs/Jets.js/blob/main/README.md) — quick start and demo link
- [package.json](https://github.com/NeXTs/Jets.js/blob/main/package.json) — version 0.15.0, MIT licensed
- Project homepage: https://jets.js.org/

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: NeXTs/Jets.js

Summary: Found 12 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Identity risk - Identity risk requires verification.

## 1. Identity risk - Identity risk requires verification

- Severity: medium
- Evidence strength: runtime_trace
- Finding: Project evidence flags a identity risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Repro command: `npm install jets`
- Evidence: identity.distribution | https://github.com/NeXTs/Jets.js

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/NeXTs/Jets.js/issues/43

## 3. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/NeXTs/Jets.js/issues/28

## 4. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/NeXTs/Jets.js/issues/33

## 5. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a capability evidence risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/NeXTs/Jets.js/issues/5

## 6. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/NeXTs/Jets.js

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/NeXTs/Jets.js

## 8. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/NeXTs/Jets.js

## 9. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/NeXTs/Jets.js

## 10. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/NeXTs/Jets.js/issues/44

## 11. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/NeXTs/Jets.js

## 12. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/NeXTs/Jets.js

<!-- canonical_name: NeXTs/Jets.js; human_manual_source: deepwiki_human_wiki -->
