Skip to content

Interactive Hover Button

A button whose label slides away to an arrow, or to a second label with an arrow, on hover and keyboard focus. Builds on Button.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

import { InteractiveHoverButton } from "@rdloom/react";

export default function InteractiveHoverButtonBasicExample() {
  return (
    <div className="flex w-full justify-center">
      <InteractiveHoverButton>Get started</InteractiveHoverButton>
    </div>
  );
}

Installation

npx rdloom add interactive-hover-button

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/interactive-hover-button.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { InteractiveHoverButton } from "@rdloom/react";

<div className="flex w-full justify-center">
  <InteractiveHoverButton>Get started</InteractiveHoverButton>
</div>

With hover label

import { InteractiveHoverButton } from "@rdloom/react";

export default function InteractiveHoverButtonWithHoverLabelExample() {
  return (
    <div className="flex w-full flex-wrap items-center justify-center gap-4">
      <InteractiveHoverButton hoverLabel="Read it" variant="secondary" size="lg">
        Read the guide
      </InteractiveHoverButton>
      <InteractiveHoverButton hoverLabel="Open" variant="ghost">
        Open the docs
      </InteractiveHoverButton>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

Button label. This is the accessible name.

nodenone
hoverLabel

Optional wording shown on hover and focus, next to the arrow. It is visual only and should say the same thing as the label. Without it only the arrow appears.

stringnone
variant

Visual emphasis, as on Button.

"primary" | "secondary" | "ghost" | "danger""primary"
size

Height, padding and font size, as on Button.

"sm" | "md" | "lg""md"
isDisabled

Prevents interaction, dims the button and turns the effect off.

booleanfalse
isLoading

Shows a spinner and blocks presses; the pending state is announced.

booleanfalse
onPress

Called when the button is pressed by mouse, touch or keyboard.

() => voidnone

Accessibility

Role button, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Tab focuses it and shows the same effect as hover
  • Enter or Space presses it

Screen readers announce

  • Announced exactly as a Button: its label, as a button; the effect adds nothing to what is read

What your code must do

  • The effect is the same for mouse hover and keyboard focus (focus-visible), so keyboard users see it too
  • The alternate label and arrow are decoration, hidden from assistive technology; the accessible name is always the main label
  • On touch screens there is no hover, so the button stays still
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), and inside an rdm-still container
  • A disabled or loading button does not animate
  • The arrow flips in right-to-left layouts
  • Optional: it is a separate component, so projects that do not add it carry none of its code

Guidelines

Use it when

  • A call to action on a landing page that should feel responsive
  • A link-like action that leads somewhere, where the arrow adds meaning

Avoid it when

  • Dense toolbars or forms, where plain Button is calmer
  • Destructive actions, where a changing label could confuse

Don't

  • A hover label that says something different from the main label
  • A hover label much longer than the main label: it is clipped to the button's width

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-action-primary
  • --rd-color-action-on-primary
  • --rd-color-action-danger
  • --rd-color-surface-default
  • --rd-color-text-default
  • --rd-color-border-default
  • --rd-color-focus-ring
  • --rd-radius-control