JSFiddle - React, Tailwind, and code Playground
HTML
<form>
<input id="search" type="text"/>
</form>
<p>
<span>Lorem ipsum dolor sit amet</span>, <span>consectetur adipiscing elit</span>. <span>Suspendisse orci velit</span>, <span>sagittis non elit id</span>, <span>placerat blandit leo</span>. <span>Etiam eu erat at nunc aliquam</span> <span>eleifend non vel libero</span>. <span>In ac mauris sit amet velit</span> <span>luctus faucibus</span>. <span>In at vulputate libero</span>. <span>Vestibulum non orci velit</span>. <span>Sed aliquam ante eget odio commodo</span> <span>condimentum</span>. <span>Suspendisse blandit at ante at condimentum</span>. <span>Duis id iaculis nunc</span>, <span>et pretium tortor</span>. <span>Ut posuere tellus at est accumsan</span> <span>semper</span>. <span>Morbi vulputate dapibus nisl varius vestibulum</span>. <span>Suspendisse ipsum mi</span>, <span>venenatis at elit eu</span>, <span>porta faucibus lorem</span>. <span>Integer commodo maximus neque tristique tempor</span>. <span>In hac habitasse platea dictumst</span>. <span>Fusce tincidunt ut felis non pharetra</span>.
</p>
<p>
<span>Donec dictum faucibus massa at accumsan</span>. <span>Aliquam erat volutpat</span>. <span>Donec et nibh fringilla nisl tempor</span> <span>pretium</span>. <span>Pellentesque justo ante</span>, <span>tincidunt non felis id</span>, <span>gravida interdum augue</span>. <span>Phasellus dictum tempus dolor et imperdiet</span>. <span>Maecenas at ornare erat</span>. <span>Integer pretium diam nisl</span>, <span>eget vestibulum orci pretium sit amet</span>. <span>Nunc consectetur interdum turpis eget tincidunt</span>. <span>Donec at facilisis arcu</span>. <span>Suspendisse tempus purus vel purus sollicitudin</span> <span>pellentesque nec in arcu</span>. <span>Morbi purus lectus</span>, <span>tempus non sem vitae</span>, <span>feugiat elementum est</span>. <span>Vivamus laoreet nulla ut urna dignissim</span>, <span>elementum dapibus sem gravida</span>. <span>Fusce pretium porttitor libero</span>, <span>sed...
CSS
form {
position: fixed;
top: .5rem;
width: 100vw;
}
input {
width: 90%;
}
form + p{
clear:both;
margin-top: 2.5rem;
}
JavaScript
const form = document.querySelector('form');
form.addEventListener('submit', doSearch)
form.addEventListener('input', doSearch);
let timeout;
function doSearch(e){
e.stopPropagation();
e.preventDefault();
if(timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(()=>{
timeout = null;
const input = document.querySelector('input'),
car = input.selectionStart,
pos = document.documentElement.scrollTop;
findAll(input.value);
document.documentElement.scrollTop = pos;
setTimeout(()=>{
input.focus();
input.setSelectionRange(car,car);
},0);
},200);
}
function findAll(text){
window.getSelection().empty();
[...document.querySelectorAll('.sel')].forEach(s=>s.remove());
let found = 0;
while(window.find(text)) {
for(let rect of window.getSelection().getRangeAt(0).getClientRects())
createSel(rect);
found++;
}
window.getSelection().empty();
function createSel(rect){
let background = '#ff04',
position='absolute',
el = document.createElement('div'),
{top,width,height,left} = rect;
el.classList.add('sel');
top += document.documentElement.scrollTop;
[top,width,height,left] = [top,width,height,left].map(v=>v+'px');
Object.assign(el.style, {background,position,top,width,height,left});
document.body.appendChild(el);
return el;
}
}