# Glitch Button

> Glitch button with cyan and magenta channel slicing on hover; respects reduced motion.

- Author: Atelier UI
- License: MIT
- Page: https://chromotion.dev/en/components/glitch-button
- Site: Atelier UI (https://chromotion.dev)

## Install

```bash
npx shadcn@latest add https://chromotion.dev/r/glitch-button.json
```

Stack: React + TypeScript + Tailwind CSS v4, shadcn/ui conventions. `cn` comes from `@/lib/utils`.

## Dependencies

No extra dependencies.

## Usage

```tsx title="components/glitch-button-demo.tsx"
import { GlitchButton } from "@/components/glitch-button"

export default function GlitchButtonDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-6 rounded-2xl bg-neutral-900 p-12">
      <GlitchButton>Hack</GlitchButton>
      <GlitchButton>System</GlitchButton>
    </div>
  )
}
```

## Source

```tsx title="components/glitch-button.tsx"
import * as React from "react"

import { cn } from "@/lib/utils"

const keyframes = `
@keyframes glitch-button-a{0%,100%{clip-path:inset(0 0 100% 0);transform:translate(0)}20%{clip-path:inset(10% 0 60% 0);transform:translate(-3px,1px)}40%{clip-path:inset(50% 0 20% 0);transform:translate(3px,-1px)}60%{clip-path:inset(80% 0 2% 0);transform:translate(-2px,0)}80%{clip-path:inset(30% 0 45% 0);transform:translate(2px,1px)}}
@keyframes glitch-button-b{0%,100%{clip-path:inset(100% 0 0 0);transform:translate(0)}20%{clip-path:inset(60% 0 10% 0);transform:translate(3px,-1px)}40%{clip-path:inset(15% 0 55% 0);transform:translate(-3px,1px)}60%{clip-path:inset(2% 0 80% 0);transform:translate(2px,0)}80%{clip-path:inset(45% 0 30% 0);transform:translate(-2px,-1px)}}
`

export interface GlitchButtonProps extends Omit<React.ComponentProps<"button">, "children"> {
  children: string
}

export function GlitchButton({ children, className, ...props }: GlitchButtonProps) {
  return (
    <button
      type="button"
      className={cn(
        "group relative inline-flex h-12 items-center justify-center bg-neutral-950 px-9 font-mono text-sm font-bold tracking-[0.25em] text-white uppercase select-none",
        "border border-white/20 transition-colors hover:border-white/60",
        "focus-visible:ring-2 focus-visible:ring-fuchsia-400 focus-visible:outline-none",
        "disabled:pointer-events-none disabled:opacity-50",
        className
      )}
      {...props}
    >
      <style href="glitch-button" precedence="default">
        {keyframes}
      </style>
      <span className="relative">{children}</span>
      <span
        aria-hidden
        className="pointer-events-none absolute inset-0 flex items-center justify-center text-cyan-300 opacity-0 mix-blend-screen group-hover:opacity-100 motion-reduce:hidden"
        style={{ animation: "glitch-button-a 0.8s steps(1) infinite" }}
      >
        {children}
      </span>
      <span
        aria-hidden
        className="pointer-events-none absolute inset-0 flex items-center justify-center text-fuchsia-400 opacity-0 mix-blend-screen group-hover:opacity-100 motion-reduce:hidden"
        style={{ animation: "glitch-button-b 0.8s steps(1) infinite" }}
      >
        {children}
      </span>
    </button>
  )
}
```
