Contour Magnet
One outline glides between native links and buttons while their hit areas stay put.
Field notes · 2026
Ideas in motion
Three recent dispatches from the studio archive.
Open studio · Saturday
Workshop schedule
Small-group sessions with the people who make the work.
09:30 · Print and paper
Press room · 8 places
13:00 · Type in space
Letter room · 5 places
Customise
Code
<CursorContourMagnet>
{/* native links and buttons marked data-contour-target */}
</CursorContourMagnet>Contour Magnet draws one lightweight outline around the native link or button beneath a fine pointer. Mark eligible controls with data-contour-target; the contour moves between their measured boxes while labels, layout and hit areas remain fixed.
The effect is decorative and pointer-only. The operating-system cursor, link and button semantics, keyboard focus rings and actions stay in the consumer's hands. Touch, reduced motion, print, offscreen and no-JavaScript use leave the native controls complete without the contour.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/cursor-contour-magnetUsage
import { CursorContourMagnet } from "@/components/ui/cursor-contour-magnet";
export default function Page() {
return (
<CursorContourMagnet className="grid gap-4">
<a href="/journal" data-contour-target className="text-base underline">
Read the field notes
</a>
<button type="button" data-contour-target>
Reserve a workshop seat
</button>
</CursorContourMagnet>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | required | Consumer-owned content. Only marked native links and buttons can attract the contour. |
| className | string | undefined | Additional classes merged onto the root region. |
Customisation
Mark only the links and buttons that should attract the contour. Set --contour-magnet-ink to a semantic theme colour and --contour-magnet-duration to a duration such as 240ms on this region or an ancestor. The root's className controls its layout; control labels, focus styling and actions remain consumer-owned.
<CursorContourMagnet
className="grid gap-4 [--contour-magnet-ink:var(--ring)] [--contour-magnet-duration:240ms]"
>
<a href="/journal" data-contour-target>Read the field notes</a>
<button type="button" data-contour-target>Reserve a seat</button>
</CursorContourMagnet>Frequently asked questions
- Which elements can attract the contour?
- Only native anchor links with an href and native buttons that carry data-contour-target. Marked non-native elements and nested marked targets are ignored.
- Does it move or replace my controls?
- No. The component measures each target and moves one aria-hidden outline. It never changes target styles or hit areas, and it never hides or replaces the operating-system pointer.
- What happens with touch, keyboard focus or reduced motion?
- Touch and coarse pointers, keyboard focus, reduced motion and print use the native links and buttons without the optional contour. Keep a visible focus style on every control.