- 🔦 Generate a 'spotlight' that follows the size and position of any active target.
- 👟 Auto-updated after resizing or DOM changing.
- ⚡️ Options to fit any position between smooth effect to high-efficiency performance.
- 🪩 Apply customized style to the 'light' easily.
- 💽 ≈ 2kB minzipped.
![use-spotlight-demo](https://private-user-images.githubusercontent.com/1435457/281972299-ef54d5a7-460e-4396-a6c8-bf39703ed85e.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkwNTY3NjMsIm5iZiI6MTczOTA1NjQ2MywicGF0aCI6Ii8xNDM1NDU3LzI4MTk3MjI5OS1lZjU0ZDVhNy00NjBlLTQzOTYtYTZjOC1iZjM5NzAzZWQ4NWUuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIwOCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMDhUMjMxNDIzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZmM0OGViODUyOWI0NDVhNWNhODZhZjhjZGQ3Y2Y0MzY5NzIzMDhhMzAxNDYyZTNhMDNkMzE0YjFmNDY4ODdhOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.k0pP_zAUe1IsCu9MmR--RnbHT3FAbOzNYSVSUDo8KAA)
spotlight-demo.mov
Description | Live demo |
---|---|
Basic | |
Auto-updated resize | |
Auto-updated DOM change | |
Throttle | |
Custom light style | |
Pseudo light |
Note
- An animated active indicator for a component like
<ToggleButton>
,<Tabs>
. - A highlight effect for a self-controlled focused system, like the result list of a
<SearchBar>
. - ...
npm install use-spotlight
+import { useSpotlight } from 'use-spotlight'
() => {
const [active, setActive] = useState(-1)
// init hook
+ const { stage, actor, style } = useSpotlight()
return (
// set ref for 'stage'
<ul
+ ref={stage}
>
{list.map(({ val }) => (
<li
onClick={() => setActive(val)}
// set ref for 'actor'
+ ref={val === active ? actor : null}
>
{val}
</li>
))}
// set 'style' to the light
+ <i style={style} />
</ul>
)
}
Parameters: SpotlightOptions
throttleWait
: The number of milliseconds to throttle invocations to.default: 0
stageBorderEdge
: With default setting, the 'light' will be positioned relative to the padding edge of the 'stage', which will cause an offset if 'stage' has borders. Set totrue
, if want to use the border edge, which will hurt performance but be more accurate on the position.default: false
stageMutation
: Enable watching 'stage'childlist
subtree
DOM mutation.default: false
lightPseudo
:::before
or::after
to enable pseudo element as 'light'. In this mode, there's no need to insert a 'light' element explicitly. It's useful for case that no extra element wanted under the 'stage'.default: null
Returns: Spotlight
stage
: The RefCallback which will be assigned to node as container.actor
: The RefCallback which will be assigned to node as target to follow.style
: The CSSProperties for the node 'light'.size
: The offset[x, y, width, height]
between 'actor' and 'stage'.
Important
stageBorderEdge=true
usesgetComputedStyle()
to calculate theborder
size of 'stage', but it's bad for performance, there're other alternatives to achieve this:- Use
outline
instead ofborder
. - Override the style of 'light':
top: -1 * var(--border-top-size-stage)
,left: -1 * var(--border-left-size-stage)
- Use
stageMutation=true
add an extraMutationObserver
to the 'stage', consider using the default setting unless it can not cover some of the cases.