A lightweight, zero‑dependency JavaScript library to spotlight DOM elements with a customizable overlay, border, padding, and optional tooltip. Single or multiple elements can be highlighted, using usual selectors.
target-highlight can be used for example to setup a tutorial by highlighting elements.
- Overlay the page, carving out “holes” around target elements
- Customizable overlay color, border color, width, radius, padding
- Tooltip support (single or per‑element) with automatic positioning
- Configurable via options or global defaults
npm install target-highlight
# or
yarn add target-highlight
import {
targetHighlight,
targetHide,
defaultConfig,
HighlightOptions,
} from "target-highlight";
// Define options
const options = {
overlayColor: "#00000080", // all color formats will work
borderColor: "red", // all color formats will work
singleTooltip: true,
padding: "2px", // same as css
borderRadius: 2,
overlayZIndex: 2,
hidePointerEvents: false,
scrollToTarget: {
// Use the same options as the native scrollIntoView api
behavior: "smooth",
block: "center",
inline: "center",
},
nextCallback: () => {}, // use your callback when clicking on a button with an id of target-highlight-button-previous
previousCallback: () => {}, // use your callback when clicking on a button with an id of target-highlight-button-previous
stopCallback: () => {}, // use your callback when clicking on a button with an id of target-highlight-button-stop
tooltip: "My content", // can also be a callback returning html content
forceTooltipPosition: null, // 'top' | 'right' | 'bottom' | 'left' | null, default: null
useResizeObserver: true, // If true, will trigger a re-render when the highlighted element resizes
blockedKeys: [], // Add keyboard keys that will be inactive when the application is running
};
// Target an element using any selector
targetHighlight("#myDiv", {
...options,
tooltip: "This is my div",
});
// Or target many elements
targetHighlight(".myClass", options);
// Remove all highlights
targetHide();
Target the following css class to customize the tooltip:
.target-highlight-tooltip {
}
The tooltip can also be passed a callback returning html content:
targetHighlight("#myDiv", {
...config,
tooltip: () => {
return `
<div>
My custom tooltip
</div>
`;
},
});
When highlighting multiple elements, you may need to show individual tooltips on each element. Use the data-target-highlight-tooltip attribute on the highlighted elements to setup the individual tooltip contents. You can also use the data-target-highlight-tooltip-position to force the tooltip position ('top' | 'right' | 'bottom' | 'left'). In this case, you won't need the tooltip option normally passed to targetHighlight. Bear in mind using data attributes, the tooltip content can only be a string.
<div
class="mySelection"
data-target-highlight-tooltip="This is div 1"
data-target-highlight-tooltip-position="bottom"
>
Some content
</div>
<div
class="mySelection"
data-target-highlight-tooltip="This is div 2"
data-target-highlight-tooltip-position="left"
>
Some other content
</div>
You can create a scenario to move from step to step. Add data-step="step" on the elements part of the scenario, where step is a number.
// Define step variables
const step = {
current: 0,
max: 5,
};
// Define callbacks in options
const options = {
nextCallback: () => moveStep("next"),
previousCallback: () => moveStep("previous"),
stopCallback: targetHide,
};
// Define blocked keys
const blockedKeys = [" ", "Tab"];
// Define a function to call the library and apply event listeners
// In this example, chevron icons are added as plain svg
// Buttons with id #target-highlight-button-previous and #target-highlight-button-next will be recognized by the library, and events attached to them.
function applySteps() {
targetHighlight(`[data-step="${step.current}"]`, {
...options,
blockedKeys,
tooltip: () => {
return `<div style="position:relative; padding: 0 24px">This is step ${step.value}</div><button id="target-highlight-button-previous" style="position: absolute; top: 50%; left: 0; transform: translateY(-50%)">${chevronLeftIcon}</button><button id="target-highlight-button-next" style="position: absolute; top: 50%; right: 0; transform: translateY(-50%)">${chevronRightIcon}</button>`;
},
});
setTimeout(() => {
applyStepListeners(options);
}, 10);
}
// Define a function to move through the steps
function moveStep(direction) {
if (direction === "next") {
step.current += 1;
if (step.current > step.max) {
step.current = 0;
}
} else {
step.current -= 1;
if (step.current < 0) {
step.current = step.max;
}
}
applySteps();
}
Use the data-target-highlight ignore data attribute on elements never to be highlighted:
<!-- When targeting the .selection class, only one element will be highlighted -->
<div class="selection">I will be selected</div>
<div class="selection" data-target-highlight-ignore>I will not be selected</div>
Combine hidePointerEvents: false
with blocked keys, to prevent events outside of the tour.
List of all the available blockable keys:
type KeyboardNavigationKey =
| " "
| "Tab"
| "Enter"
| "ArrowUp"
| "ArrowDown"
| "ArrowLeft"
| "ArrowRight"
| "Home"
| "End"
| "PageUp"
| "PageDown"
| "Escape";
Set blocked keys in the options object:
blockedKeys: [
" ",
"Tab",
"Enter",
"ArrowUp",
"ArrowDown",
"ArrowLeft",
"ArrowRight",
"Home",
"End",
"PageUp",
"PageDown",
"Escape",
];
Blocked events will be restored when targetHide
is called.
This library does not inject CSS. To enable tooltip transitions, add for example the following to your app’s global styles:
.target-highlight-tooltip {
opacity: 1;
transition: opacity 0.3s;
will-change: opacity;
}
.target-highlight-tooltip.fade-in {
opacity: 0;
animation: fadeIn 0.3s forwards;
}
.target-highlight-tooltip.fade-out {
opacity: 1;
animation: fadeOut 0.3s forwards;
pointer-events: none;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
@keyframes fadeOut {
to {
opacity: 0;
}
}