Focus
Blurs its area except a sharp circle at the pointer, like a shallow depth of field. Opens up over controls.
npx shadcn@latest add https://hoverui.fun/ r/ focus.jsonAdds components/cursors/focus.tsx. The CLI also installs the useCursor hook it runs on, once, into your hooks folder. The files are yours from there.
Move through the preview, then hover the controls and press.Open this on a computer to move it around: it follows a mouse, not a finger.
- Kind
- Lenses
- Hook
- useCursor
- Dependencies
- None
- License
- MIT
How it behaves
Blurs its area except a sharp circle at the pointer, like a shallow depth of field; it opens up over anything clickable and racks in on press.
Usage
import { FocusCursor } from "@/components/cursors/focus";
export function Section() {
return (
<section>
<FocusCursor />
{/* this section now wears Focus */}
</section>
);
}Put it inside <body> in your root layout to wear it on every page. Nested cursors take over inside their own element.
Props
- className
- Colors any outline and the pointer dot through currentColor, e.g. text-pink-500. Keep blend modes and filters off it: either would cut the lens off from the page it sees.
- Hover targets
- a, button, input, select, textarea, label, [role=button], [data-cursor-label]
Source
"use client";
import { useRef } from "react";
import { cursorRoot, useCursor } from "@/hooks/use-cursor";
/** Blurs its area except a sharp circle at the pointer, like a shallow depth of field; it opens up over anything clickable and racks in on press. */
export function FocusCursor({ className = "" }: { className?: string }) {
const r = useRef(70);
const ref = useCursor((p, el) => {
r.current += ((p.down ? 40 : p.hover ? 110 : 70) - r.current) * p.ease(10);
// The blur covers only the visible part of the area, with a hole where the pointer is.
const a = el.parentElement!.getBoundingClientRect();
const left = Math.max(a.left, 0);
const top = Math.max(a.top, 0);
const [blur, dot] = el.children as HTMLCollectionOf<HTMLElement>;
Object.assign(blur.style, {
left: `${left}px`,
top: `${top}px`,
width: `${Math.min(a.right, innerWidth) - left}px`,
height: `${Math.min(a.bottom, innerHeight) - top}px`,
maskImage: `radial-gradient(circle ${r.current}px at ${p.x - left}px ${p.y - top}px, transparent 60%, black 100%)`,
});
dot.style.transform = `translate(${p.x}px, ${p.y}px)`;
});
// No blend mode or filter on the root: either would cut the blur off from the page beneath.
return (
<div ref={ref} aria-hidden className={`${cursorRoot} ${className}`}>
<div className="absolute backdrop-blur-[3px]" />
<div className="absolute size-1.5 -translate-1/2 rounded-full bg-current" />
</div>
);
}
It runs on the useCursor hook, which has its own source and API.
More lenses cursors
- BlendInverts whatever is beneath it. Grows over anything clickable.
- GlassA lens of frosted glass that blurs whatever it passes over. Widens over anything clickable.
- GogglesNight-vision goggles that turn whatever they pass over green. They gain up over controls; a click flashes them.
- MagnifierA magnifying glass that really enlarges the page under it. Closer over controls, closer still while you hold.
- DropletA water drop that refracts the page under it. Swells over controls; a click sends ripples through the page, bending its words.
- LiquidA drop of liquid glass that bends the page at its rim. Over controls it flows out to wrap them in a glass pill; press to squeeze it.
- GlitchThe page round the pointer splits into red, green and blue and tears sideways in fits, with no frame. It takes over controls and glitches harder; a click throws a burst.
Made a cursor of your own? Contributed cursors carry their maker's name on their page.
Contribute a cursor