Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Buttons

Pro

Flow Button for React

A button framed by a calm ring whose lit half turns around the edge on hover and turns back when the pointer leaves. For React with Base UI, when a button should answer the pointer without moving at rest.

Framework
UI library

The button sits in a still, primary-colored frame, with the lower half of its edge lit. On hover or keyboard focus the light turns half a circle around the edge to the top, and a thin seam of color sweeps around the button as it goes. When the pointer leaves, it turns back.

Use it in navigation, toolbars and dense screens, where a ring that spins all the time would pull attention away from the content. For one headline action that should always move, use the Glow Border Button instead. It wraps the Button, so variant and size work as usual. The turn is a CSS transition that rotates a conic gradient under a ring-shaped mask, with no JavaScript, no animation library and nothing to add to your stylesheet. With reduced motion the light switches halves without turning.

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 { FlowButton } from "@/components/ui/flow-button";
<FlowButton>Get started</FlowButton>

Demos

Duration

duration is how long the ring takes to turn half a circle, in milliseconds, and the default is 500. It turns back at the same speed. A quick turn suits a row of buttons people sweep across; a slow one makes the seam easier to follow.

Preview width

Active

active holds the ring turned, as hover does. Use it for the current page in a nav or the option that's chosen, together with aria-current or aria-pressed so assistive tech hears the same thing. The other buttons still turn on hover.

Preview width

Accessibility

The ring and the frame are decoration and hidden from assistive tech: the button is announced and activated as any Button. On keyboard focus the ring turns as it does on hover, and the frame steps aside so the focus ring shows clearly. active is only a look; say what it means with aria-current or aria-pressed.

Enter
Activate the button.
Space
Activate the button.

FAQ

How does the edge turn?

Under the edge sits a conic gradient twice the button's width, half the primary color and half a faint seam, and a mask cuts everything but a thin ring out of it. On hover a CSS transition rotates that layer half a circle, and back when the pointer leaves; a rotation is cheap for the browser to animate.

How is it different from the Glow Border Button?

The Glow Border Button turns all the time and adds a halo. The Flow Button is still until the pointer reaches it, turns only half a circle, and has no halo, which suits navigation and dense screens.

How do I make the turn slower or faster?

Set duration, the time for half a turn in milliseconds; 500 is the default. The Duration demo shows 250 and 1200.

How do I mark the current page in a nav?

Pass active, and aria-current="page" for assistive tech. The ring stays turned, as in the Active demo.

What colors does it use?

The primary color for the lit half and the frame, and a faint mix of the foreground color for the seam, so it follows your theme in light and dark mode.

Which way does it turn in a right-to-left layout?

The other way round: the ring is mirrored, so the seam sweeps counterclockwise.

What happens with reduced motion?

The ring doesn't turn. On hover or focus the light moves to the top half at once, so the state still shows.

API Reference

FlowButton

data-slot="flow-button-border"

PropType
active?boolean

Hold the ring turned, as hover does: for the current page in a nav, or the option that's chosen.

Default
false
children?ReactNode

The label, inside the ring.

duration?number

How long the ring takes to turn half a circle, in milliseconds; it turns back as fast when the pointer leaves.

Default
500
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
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.

AttributeType
data-active?string

Present when active is set.

CSS variableType
--flow-button-durationstring

Half a turn of the ring (500ms).

All 35 buttons