Skip to content

Slice Shear Hover

Display type cut into horizontal bands that fan apart under the pointer.

Freebrutalisteditorialplayful
Category
Text Effects
Added
2026-09-20
Deps
none
Updated
2026-09-20
Preview
VIBERDYHover

Props

6
16
Accent outer bands
No runtime dependencies
"use client";

import { useState } from "react";

export function HoverSliceShear({
  text = "VIBERDY",
  slices = 6,
  shear = 16,
  accentEdges = true,
}: {
  text?: string;
  slices?: number;
  shear?: number;
  /** Tint the top and bottom bands while sheared, so the fan reads. */
  accentEdges?: boolean;
}) {
  const [hovered, setHovered] = useState(false);

  return (
    <span
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      className="relative inline-block cursor-pointer select-none"
    >
      {/* The one accessible copy of the string. */}
      <span className="sr-only">{text}</span>

      <span aria-hidden className="relative block text-6xl font-black leading-none tracking-tight">
        {/* Invisible copy establishes the box for the absolute slices. */}
        <span className="invisible block">{text}</span>

        {Array.from({ length: slices }).map((_, i) => {
          const top = (i / slices) * 100;
          const bottom = 100 - ((i + 1) / slices) * 100;
          const direction = i % 2 === 0 ? 1 : -1;
          // Ease the offset toward the vertical centre so the bands fan out
          // instead of shearing like a uniform comb.
          const falloff = 1 - Math.abs(i - (slices - 1) / 2) / slices;
          const offset = hovered ? direction * shear * falloff : 0;

          return (
            <span
              key={i}
              className="absolute inset-0 block transition-transform duration-500 ease-[cubic-bezier(0.16,1,0.3,1)]"
              style={{
                clipPath: "inset(" + top + "% 0% " + bottom + "% 0%)",
                transform: "translateX(" + offset + "px)",
                transitionDelay: i * 18 + "ms",
                color:
                  accentEdges && hovered && (i === 0 || i === slices - 1)
                    ? "#3d7bff"
                    : undefined,
              }}
            >
              {text}
            </span>
          );
        })}
      </span>
    </span>
  );
}
Notes

About this text effect

Cutting a word into bands and sliding alternate rows is a familiar trick; what usually gives it away as a demo is that every band moves the same distance, producing a mechanical comb. Weighting each band's offset by its distance from the vertical centre turns the same idea into a fan, which is what reads as designed rather than generated — the 18ms stagger does the rest, so the bands arrive in sequence instead of snapping as one. The construction is worth understanding before copying: the word is rendered once per band, each copy clipped to its own horizontal slice with clip-path inset, which keeps every band as real text at its real position rather than a transformed image. That duplication is also the trap. All but one copy must be hidden from assistive technology, or a six-band headline is announced six times; the pattern here keeps a single screen-reader copy and marks the visual stack decorative. Because clip-path and transform are both compositor-friendly, the whole effect stays off the layout path — but it is still an effect for one headline per page, not for body copy.

Curator’s note

Built for viberdy 2.0. The centre-weighted falloff is the difference between this and the flat alternating version you see everywhere.

Related

Pairs well with

Matched on shared tags and category — the entries most likely to be used alongside this one.

Featured
New

Weight Wave Text

text effects

Per-character variable font weight that swells around the pointer and drifts when idle.

textvariable-fonthover
Trending
New

Extruded Type Tilt

text effects

Display type with a solid extrusion that swings around as the pointer moves.

text3dextrude
Featured
NewPro

RGB channels of a headline separate toward the pointer and recombine to white.

textchromatichover