Skip to content

Commit

Permalink
Allow search in children
Browse files Browse the repository at this point in the history
  • Loading branch information
fzaninotto committed Apr 16, 2024
1 parent 1010a31 commit 85c456a
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 76 deletions.
70 changes: 58 additions & 12 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,16 @@

Highlight search term in a page. Vanilla JS, compatible with frontend frameworks (React, Vite, Angular, etc).

Does not modify the DOM. Relies on the browser's [CSS Custom Highlight API](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API).
Does not modify the DOM. Relies on the browser's [CSS Custom Highlight API](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API) ([limited browser support](https://caniuse.com/?search=CSS.Highlights)).

This is not a syntax highlighter API. It highlights text in a page based on a search term.

## Usage

The library exports a single function that expects a search term and a CSS selector of the element to search in.

```html
<script type="module">
import { default as highlightSearchTerm } from "https://cdn.jsdelivr.net/npm/highlight-search-term@0.0.8/src/index.js";
const search = document.getElementById("search");
search.addEventListener("input", () => {
highlightSearchTerm({
search: search.value,
selector: ".content p"
});
});
</script>
```js
highlightSearchTerm({ search: search.value, selector: ".content" });
```

This creates a highlight range named "search" that you can highlight with CSS, e.g.:
Expand All @@ -30,6 +23,59 @@ This creates a highlight range named "search" that you can highlight with CSS, e
}
```

You can use it directly in your HTML:

```html
<script type="module">
import { highlightSearchTerm } from "https://cdn.jsdelivr.net/npm/highlight-search-term@0.0.9/src/index.js";
const search = document.getElementById("search");
search.addEventListener("input", () => {
highlightSearchTerm({
search: search.value,
selector: ".content"
});
});
</script>
```

Or, if you use a bundler like Vite, you can import it in your JavaScript:

```js
import { highlightSearchTerm } from "highlight-search-term";
const search = document.getElementById("search");
search.addEventListener("input", () => {
highlightSearchTerm({
search: search.value,
selector: ".content"
});
});
```

If you use a frontend framework like React, you can use it in a `useEffect` hook:

```jsx
import { useEffect, useState } from "react";

export default function App() {
const [search, setSearch] = useState("");
useEffect(() => {
highlightSearchTerm({ search, selector: ".content" });
}, [search]);
return (
<div>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
);
}
```

## License

MIT, courtesy of [Marmelab](https://marmelab.com)
109 changes: 90 additions & 19 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,108 @@
<head>
<title>highlight-search-term</title>
<style>
body {
font-family: Roboto, Open Sans, sans-serif;
margin: 0;
padding: 0;
font-size: 15px;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
::highlight(search) {
background-color: yellow;
color: black;
}
</style>
</head>
<body>
<h1>highlight-search-term</h1>
<p>
highlight-search-term is a simple JavaScript library that highlights
search terms in a text.
</p>
<h2>Usage</h2>
<pre><code class="language-javascript">highlightSearchTerm('lorem', '.content');</code></pre>
<h2>Example</h2>
<p>
Use the following search input to highlight the search term in the content
below:
</p>
<div>
<input type="text" id="search" />
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
<div class="container">
<h1>highlight-search-term</h1>
<p>
A JavaScript library that highlights search terms in a page without
modifying the DOM.
</p>
<p>
<a href="https://github.com/marmelab/highlight-search-term">GitHub</a> -
<a href="https://www.npmjs.com/package/highlight-search-term">Npm</a>
</p>
<h2>Usage</h2>
<pre><code class="language-javascript">import { highlightSearchTerm } from 'highlight-search-term';

highlightSearchTerm('lorem', '.content');
</code></pre>
<h2>Example</h2>
<p>
Use the following search input to highlight the search term in the
content below:
</p>
<div>
<input type="text" id="search" value="lorem" />
</div>
<div class="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac felis
eget est consequat sagittis nec commodo tellus. Donec aliquam lacus
vehicula urna scelerisque gravida sed ut felis. Cras eget vehicula ex.
Nullam sed justo id leo euismod faucibus. Vestibulum tincidunt in
felis nec rutrum. In lobortis dictum augue non luctus. Quisque egestas
neque at maximus placerat. Duis ornare dictum suscipit. Vivamus
molestie est et ultricies finibus.
</p>

<p>
Phasellus id magna in enim vulputate luctus. Curabitur nec enim non
nisl vulputate cursus. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Vestibulum eget mi malesuada, dapibus magna ut,
aliquam ipsum. Donec eleifend hendrerit nibh, a euismod neque ultrices
hendrerit. Aenean id ipsum sit amet quam iaculis posuere. Class aptent
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
himenaeos. Aenean malesuada ultrices sapien quis pulvinar. Interdum et
malesuada fames ac ante ipsum primis in faucibus. Nunc non lacus eget
nibh finibus ullamcorper fringilla vel sem. Duis sollicitudin sem ac
libero imperdiet, nec laoreet erat scelerisque. Pellentesque habitant
morbi tristique senectus et netus et malesuada fames ac turpis
egestas. Vestibulum nec ligula vulputate nisi venenatis rutrum.
</p>

<p>
Aenean eget bibendum urna. Quisque eget porttitor tellus, ac tempor
neque. Vivamus eleifend, eros non suscipit ultricies, felis mi cursus
ex, dignissim convallis tellus est sed sem. Duis est nisl, tincidunt
vel enim nec, gravida porttitor ipsum. Maecenas dictum id mi non
condimentum. Sed at metus enim. Nullam vel tristique justo, ac porta
urna. Aliquam ullamcorper fringilla vehicula. Praesent ac sem euismod,
scelerisque ligula eu, venenatis felis. Fusce efficitur metus vel
magna fringilla convallis et a ex. Nulla maximus libero turpis, ac
euismod nisl facilisis sit amet. Quisque faucibus consectetur laoreet.
Etiam at vulputate mi. Pellentesque sed lectus rhoncus, rhoncus sem
sit amet, faucibus neque. Aliquam non auctor libero, vehicula
hendrerit tortor.
</p>
</div>
<h2>Limitations</h2>
<p>
This library uses the
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API"
>CSS Custom Highlight API</a
>, which works on all evergreen browsers except Firefox.
</p>
<h2>License</h2>
<p>MIT</p>
</div>
</body>
<script type="module">
import { default as highlightSearchTerm } from "https://cdn.jsdelivr.net/npm/highlight-search-term@0.0.8/src/index.js";
import { highlightSearchTerm } from "https://cdn.jsdelivr.net/npm/highlight-search-term@0.0.9/src/index.js";
const search = document.getElementById("search");
search.addEventListener("input", () => {
highlightSearchTerm({ search: search.value, selector: ".content p" });
highlightSearchTerm({ search: search.value, selector: ".content" });
});
setTimeout(() => {
highlightSearchTerm({ search: search.value, selector: ".content" });
}, 100);
</script>
</html>
38 changes: 0 additions & 38 deletions doc/index.html

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "highlight-search-term",
"version": "0.0.8",
"version": "0.0.9",
"description": "Highlight search term in a page. Vanilla JS, compatible with frontend frameworks (React, Vite, Angular, etc).",
"repository": "marmelab/highlight-search-term",
"homepage": "https://github.com/marmelab/highlight-search-term",
Expand Down
2 changes: 1 addition & 1 deletion src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ declare module "highlight-search-term" {
customHighlightName?: string;
}
function highlightSearchTerm(params: HighlightSearchTermParams): void;
export = highlightSearchTerm;
export { highlightSearchTerm };
}
26 changes: 21 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Highlight search term in the selected elements
*
* @example
* import { default as highlightSearchTerm } from "https://cdn.jsdelivr.net/npm/highlight-search-term@0.0.8/src/index.js";
* import { highlightSearchTerm } from "highlight-search-term";
* const search = document.getElementById("search");
* search.addEventListener("input", () => {
* highlightSearchTerm({ search: search.value, selector: ".content p" });
* highlightSearchTerm({ search: search.value, selector: ".content" });
* });
*/
const highlightSearchTerm = ({
Expand All @@ -27,8 +27,12 @@ const highlightSearchTerm = ({
}
const ranges = [];
const elements = document.querySelectorAll(selector);
Array.from(elements).forEach((element) => {
ranges.push(...getRangesForSearchTermInElement(element, search));
Array.from(elements).map((element) => {
getTextNodesInElementContainingText(element, search).forEach((node) => {
ranges.push(
...getRangesForSearchTermInElement(node.parentElement, search)
);
});
});
if (ranges.length === 0) return;
const highlight = new Highlight(...ranges); // eslint-disable-line no-undef
Expand All @@ -37,6 +41,18 @@ const highlightSearchTerm = ({
CSS.highlights.set(customHighlightName, highlight);
};

const getTextNodesInElementContainingText = (element, text) => {
const nodes = [];
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
let node;
while ((node = walker.nextNode())) {
if (node.textContent?.toLowerCase().includes(text)) {
nodes.push(node);
}
}
return nodes;
};

const getRangesForSearchTermInElement = (element, search) => {
const ranges = [];
if (!element.firstChild) return ranges;
Expand All @@ -53,4 +69,4 @@ const getRangesForSearchTermInElement = (element, search) => {
return ranges;
};

export default highlightSearchTerm;
export { highlightSearchTerm };

0 comments on commit 85c456a

Please sign in to comment.