Web InnoventixFreeCode

Blinds Vertical Effect

Original · free

Vertical blinds open to reveal the image on hover.

byWeb InnoventixReact + Tailwind
blindsverticalimageeffect
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/imgfx-blinds-vertical.json
imgfx-blinds-vertical.tsx
"use client";

import { useId } from "react";

const SLAT_COUNT = 9;

export default function ImgfxBlindsVertical() {
  const slats = Array.from({ length: SLAT_COUNT }, (_, i) => i);
  const rawId = useId();
  const uid = `imgfxBlindsVertical_${rawId.replace(/[^a-zA-Z0-9]/g, "")}`;

  return (
    <section className="relative w-full bg-white px-6 py-20 dark:bg-neutral-950 sm:px-10 sm:py-28">
      <style>{`
        .${uid}-slats {
          perspective: 1400px;
          perspective-origin: left center;
        }
        .${uid}-slat {
          transform-origin: 0% 50%;
          transform: rotateY(0deg);
          transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1),
            filter 700ms cubic-bezier(0.22, 1, 0.36, 1);
          transition-delay: calc(var(--imgfx-i) * 55ms);
          backface-visibility: hidden;
        }
        .${uid}-stage:hover .${uid}-slat,
        .${uid}-stage:focus-visible .${uid}-slat,
        .${uid}-stage:focus-within .${uid}-slat {
          transform: rotateY(-88deg);
          filter: brightness(1.35);
        }
        @media (prefers-reduced-motion: reduce) {
          .${uid}-slat {
            transition: none;
            transition-delay: 0ms;
          }
          .${uid}-stage:hover .${uid}-slat,
          .${uid}-stage:focus-visible .${uid}-slat,
          .${uid}-stage:focus-within .${uid}-slat {
            transform: rotateY(0deg);
            opacity: 0;
          }
        }
      `}</style>

      <div className="mx-auto flex max-w-2xl flex-col items-center text-center">
        <p className="text-xs font-semibold uppercase tracking-[0.25em] text-indigo-600 dark:text-indigo-400">
          Image Effect
        </p>
        <h2 className="mt-3 text-2xl font-bold tracking-tight text-slate-900 dark:text-white sm:text-3xl">
          Vertical Blinds Reveal
        </h2>
        <p className="mt-3 text-sm text-slate-600 dark:text-slate-400">
          Slatted louvres pivot open in a staggered cascade to unveil the photo beneath.
        </p>

        <div
          className={`${uid}-stage group relative mt-10 aspect-[4/3] w-full overflow-hidden rounded-2xl bg-slate-100 shadow-xl ring-1 ring-slate-900/10 outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:bg-neutral-900 dark:ring-white/10`}
          tabIndex={0}
          role="img"
          aria-label="A workspace photograph revealed as vertical blinds pivot open"
        >
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img
            src="/img/gallery/g07.webp"
            alt="Sunlit workspace with a laptop, notebook and coffee on a wooden desk"
            loading="lazy"
            draggable={false}
            className="absolute inset-0 h-full w-full object-cover"
          />

          <div className={`${uid}-slats pointer-events-none absolute inset-0`} aria-hidden="true">
            {slats.map((i) => (
              <div
                key={i}
                className={`${uid}-slat absolute top-0 h-full bg-gradient-to-r from-slate-200 via-slate-100 to-slate-300 shadow-[inset_-1px_0_0_rgba(15,23,42,0.14),inset_1px_0_0_rgba(255,255,255,0.55)] dark:from-neutral-800 dark:via-neutral-700 dark:to-neutral-900 dark:shadow-[inset_-1px_0_0_rgba(0,0,0,0.5),inset_1px_0_0_rgba(255,255,255,0.06)]`}
                style={{
                  left: `${(i * 100) / SLAT_COUNT}%`,
                  width: `${100 / SLAT_COUNT}%`,
                  ["--imgfx-i" as string]: i,
                }}
              />
            ))}
          </div>

          <span className="pointer-events-none absolute bottom-3 left-1/2 -translate-x-1/2 rounded-full bg-slate-900/70 px-3 py-1 text-[11px] font-medium text-white opacity-100 backdrop-blur-sm transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0 dark:bg-white/15">
            Hover or focus to open
          </span>
        </div>
      </div>
    </section>
  );
}

Dependencies

None (React + Tailwind only).

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →