Interactive Hover Button
Interactive Hover Button starts as an outlined pill with a small dot at its left edge. On hover the dot grows to cover the whole button, the label shifts over to make room, and an arrow fades in at the trailing edge.
All three moves are CSS transitions on the group-hover state, so the effect works on touch devices as a :hover no-op and never runs a frame of JavaScript.
Usage
The dot grows into a full fill on hover while the label slides over and an arrow fades in.
<template>
<div class="flex w-full flex-col items-center gap-4 py-6">
<MInteractiveHoverButton>
Get started
</MInteractiveHoverButton>
</div>
</template>
Customize
Customize
No customizable props detected for this component.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | '' | CSS classes for the button itself. The pill's w-36 lives in the theme, so widen it here when the label is longer. |
Slots
| Slot | Props | Description |
|---|---|---|
default | - | The button's label, rendered between the dot and the arrow. |
UI
This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.interactiveHoverButton in app.config.ts.
| Prop | Type | Default | Description |
|---|---|---|---|
ui | object | - | Per-slot classes merged over the theme defaults. |
| Slot | Props | Description |
|---|---|---|
root | - | group relative inline-flex h-10 w-36 items-center justify-center overflow-hidden rounded-full border border-default bg-background text-sm font-medium text-highlighted transition-colors duration-300 hover:border-primary |
dot | - | absolute left-3 top-1/2 size-2 -translate-y-1/2 rounded-full bg-primary transition-all duration-300 ease-out group-hover:left-0 group-hover:top-0 group-hover:size-full group-hover:translate-y-0 group-hover:rounded-none |
label | - | relative z-10 flex items-center gap-1 transition-all duration-300 group-hover:translate-x-2 group-hover:text-inverted |
arrow | - | relative z-10 size-4 -translate-x-2 opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100 group-hover:text-inverted |
Accessibility
The root is a real <button type="button"> and the arrow is aria-hidden. The fill and the arrow only appear on hover, so the resting state still carries the full label and the label never disappears behind the fill — it just changes colour.