Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Buttons

Pro

Border Trace Button for React

A button whose edge is drawn by a glowing line on hover, like a pen going once around it. For React with Base UI, when an action should feel precise and deliberate.

Framework
UI library

When the pointer arrives or the button takes keyboard focus, a line starts at the left edge and runs once around the button until the outline is closed, with a soft glow. A faint fill of the same color comes up underneath. When the pointer leaves, the line draws itself back.

Use it for actions in developer tools and technical products, such as Deploy, Run or Generate, where a crisp line suits the interface better than a fill. For a ring that's always drawn and turns on hover, use the Flow Button. It wraps the Button and starts as a ghost button in the primary color, but any variant and size work. The line is a conic gradient under a ring-shaped mask, its sweep a CSS property a transition takes from 0% to 100%; the install registers that property in your stylesheet, with no animation library. Its corners are the button's own, whatever the radius. With reduced motion the outline appears at once.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { BorderTraceButton } from "@/components/ui/border-trace-button";
<BorderTraceButton>Deploy project</BorderTraceButton>

Demos

Duration

duration is how long the line takes to go once around the button, in milliseconds, and the default is 600. It draws back at the same speed. A short trace suits a button people press often; a slow one turns hovering into a small moment.

Preview width

Color

traceColor colors the line, its glow and the faint fill under it, any CSS color. By default they take the label's color, which is the primary color on the default ghost button. Here a filled button traces in its own label color, so the line shows on its edge, and a destructive action traces in var(--destructive).

Preview width

Accessibility

The line and the fill are decoration and hidden from assistive tech: the button is announced and activated as any Button. The trace runs on keyboard focus as well as on hover, so people who tab through the page see the same cue.

Enter
Activate the button.
Space
Activate the button.

FAQ

How do I control how fast the line draws?

Set duration in milliseconds; 600 is the default. The line draws back at the same speed when the pointer leaves. The Duration demo shows 300 and 1500.

How do I change the color of the line?

Pass traceColor, such as var(--destructive). It colors the line, its glow and the fill under it. The Color demo shows two.

Do the corners match my button's radius?

Yes. The line is cut out of the button's own box with its own corners, so it follows your theme, every size and the pill prop. There's nothing to set or measure.

Does the outline stay after it's drawn?

While the pointer stays, or the button keeps keyboard focus, yes: the line holds, glowing softly. When the pointer leaves, it draws back from where it ended.

Why does the line run faster along the ends?

It sweeps around the button's center at an even turn, like a clock hand, so it crosses the short ends of a wide button quickly and takes its time along the long sides.

Can I use it with other variants and sizes?

Yes. It starts as a ghost button with a primary label, and you can pass any variant and size. The line takes the label's color, so it shows on a filled button too.

What happens with reduced motion?

The outline still appears on hover and focus, but all at once, without the drawing.

Does it work in right-to-left layouts?

Yes. In a right-to-left layout the line starts at the right edge and runs the other way around, so it starts where reading does.

API Reference

BorderTraceButton

data-slot="border-trace-button-trace"

PropType
children?ReactNode

The label, inside the line.

duration?number

How long the line takes to go once around the button, in milliseconds; it draws back as fast when the pointer leaves.

Default
600
focusableWhenDisabled?boolean

Whether the button should be focusable when disabled.

Default
false
nativeButton?boolean

Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button (for example, <div>).

Default
true
traceColor?string

The line's color, and the faint fill's under it, any CSS color. By default the label's color: the primary color on the default ghost button.

render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--border-trace-button-colorstring

The line and the fill under it (the label's color by default).

--border-trace-button-durationstring

One trip around the edge (600ms).

--border-trace-button-progressstring

How much of the edge is drawn, 0% to 100%.

All 35 buttons