ComponentsHover-only, gated a fine pointer. Niente JS, solo transform + opacity sui due layer di label.
ButtonHoverCSS
Esempio01
interactive-hover-button.tsx 001Default · hover to morph002Hero · same label, no morphTutto il catalogo, gratis
36 componenti, prompt LLM, codice copia-e-incolla.
003Discovery CTA · alt label reveals action tsxsrc/components/interactive-hover-button.tsx
import type { ButtonHTMLAttributes, ReactNode } from "react";
import { ArrowRight } from "lucide-react";
import { cn } from "@/lib/utils";
export type InteractiveHoverButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
children: ReactNode;
/** Label shown on hover. Defaults to repeating `children`. */
hoverText?: ReactNode;
className?: string;
};
/**
* <InteractiveHoverButton/> — at rest: dot + label. On fine-pointer hover:
* the accent dot expands rightward to fill the button, the rest label
* slides off to the right, and a new label slides in from the left
* with an arrow. CSS-only, gated to `hover: hover` so touch devices stay
* still.
*/
export function InteractiveHoverButton({
children,
hoverText,
className,
...rest
}: InteractiveHoverButtonProps) {
return (
<>
<style>{`
@media (hover: hover) and (pointer: fine) {
.ihb-shell:hover .ihb-fill { transform: scaleX(1); }
.ihb-shell:hover .ihb-rest { transform: translateX(140%); opacity: 0; }
.ihb-shell:hover .ihb-hover { transform: translateX(0); opacity: 1; }
}
`}</style>
<button
type="button"
{...rest}
className={cn(
"ihb-shell press group relative isolate inline-flex items-center justify-center",
"min-h-[44px] rounded-full pl-9 pr-5 py-2",
"border border-border-strong bg-bg-alt text-fg",
"font-sans text-sm font-medium",
"overflow-hidden",
className,
)}
>
<span
aria-hidden
className="ihb-fill pointer-events-none absolute inset-0 origin-left -z-10 rounded-full bg-accent"
style={{
transform: "scaleX(0)",
transition: "transform 480ms var(--ease-out)",
}}
/>
<span
aria-hidden
className="absolute left-3.5 top-1/2 size-1.5 -translate-y-1/2 rounded-full bg-accent"
/>
<span
className="ihb-rest relative inline-flex items-center"
style={{
transition:
"transform 380ms var(--ease-out), opacity 240ms var(--ease-out)",
}}
>
{children}
</span>
<span
className="ihb-hover absolute inset-0 inline-flex items-center justify-center gap-2 text-accent-fg"
style={{
transform: "translateX(-100%)",
opacity: 0,
transition:
"transform 380ms var(--ease-out), opacity 240ms var(--ease-out)",
}}
>
<span>{hoverText ?? children}</span>
<ArrowRight className="size-4" aria-hidden />
</span>
</button>
</>
);
}
Note — Sui touch device l'effetto è gated, quindi vedrai solo lo stato a riposo. Il bottone resta accessibile (label fissa, aria-label opzionale).
Prompt LLM02
Incolla in Claude o ChatGPT per generare la tua variante. Include il contesto del brand, i token e i vincoli del progetto.
Prompt · interactive-hover-button Sei un senior frontend engineer. Stai lavorando su un sito Next.js 16 + React 19 + Tailwind v4 in italiano, look chanhdai-inspired: colonna stretta 672px, Geist Sans + Geist Mono, hairline 1px, divisori a stripe diagonale, palette zinc.
Token CSS disponibili: --bg, --bg-alt, --fg, --fg-muted, --fg-soft, --border, --border-strong, --accent. Usa SEMPRE queste variabili tramite le utility tailwind generate (bg-bg, text-fg-muted, border-border, ecc.). Helper "cn" da "@/lib/utils". Niente librerie UI extra: solo lucide-react e tailwind-merge.
Genera un componente <InteractiveHoverButton>: bottone two-state con dot che si espande on hover.
Props:
- children: ReactNode (label a riposo).
- hoverText?: ReactNode (default = children).
- className?: string + ...rest.
Implementazione:
- Server component. Classe press, rounded-full, min-h-[44px], px-5 py-2, border border-border-strong bg-bg-alt text-fg.
- Span dot absolute left-3 top-1/2 size-1.5 rounded-full bg-accent.
- Span "rest" label, span "hover" label absolute con freccia ArrowRight.
- @media (hover: hover) and (pointer: fine): on hover scale(120) sul dot, translateX rest → 140%, hover → 0, opacity swap. Transition 380ms var(--ease-out).
Output: file completo src/components/interactive-hover-button.tsx.
Uso tipico03
<InteractiveHoverButton hoverText="Avvia">Get Started</InteractiveHoverButton>
Dipendenze04
- lucide-react
- tailwind-merge
- clsx
Ti è servito? Dimmelo, oppure proponi il prossimo componente.