# Liquid Fill Word Rising to a Level

A shadcn/ui block from the [@weinc](https://we.inc/components?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/weinc/liquid-fill-word-rising-to-a-level).

- Page, with a live preview: https://shadcn.exchange/r/weinc/liquid-fill-word-rising-to-a-level
- Screenshot: https://shadcn.exchange/shot/weinc/liquid-fill-word-rising-to-a-level/light.png
- Registry item: https://we.inc/r/liquid-fill-word-rising-to-a-level.json
- Listed: 2026-10-28, source last changed 2026-10-28

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/weinc/liquid-fill-word-rising-to-a-level.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Files

### `components/we-inc/liquid-fill-word-rising-to-a-level.tsx`

```tsx
import { useEffect, useId, useRef, useState } from "react";

const WORD = "REFILL";

export default function LiquidFillWordRisingToALevel() {
  const root = useRef<HTMLElement>(null);
  const [visible, setVisible] = useState(true);
  const clip = `w10lqf-${useId().replace(/[^a-zA-Z0-9]/g, "")}`;

  useEffect(() => {
    const el = root.current;
    if (!el) return;
    const io = new IntersectionObserver(([entry]) => setVisible(entry.isIntersecting));
    io.observe(el);
    return () => io.disconnect();
  }, []);

  return (
    <section
      ref={root}
      data-paused={visible ? "false" : "true"}
      className="w10lqf bg-[linear-gradient(170deg,#fcefe4_0%,#f7dccd_55%,#f1cdbf_100%)] px-5 py-16 sm:px-10 sm:py-20"
    >
      <style>{`
        .w10lqf { --w10lqf-deep: #1d6f73; --w10lqf-light: #59b3ad; --w10lqf-outline: #1a4f53; --w10lqf-level: -170px; }
        .w10lqf-rise { transform: translateY(0); animation: w10lqf-rise 2.2s cubic-bezier(0.22, 1, 0.36, 1) 0.1s forwards; }
        .w10lqf-bob { animation: w10lqf-bob 3.6s ease-in-out infinite; }
        .w10lqf-front { animation: w10lqf-drift 4.5s linear infinite; }
        .w10lqf-back { animation: w10lqf-drift 7s linear infinite reverse; }
        .w10lqf-bubble { opacity: 0; transform-box: fill-box; animation: w10lqf-bubble 4s ease-in infinite; }
        @keyframes w10lqf-rise { to { transform: translateY(var(--w10lqf-level)); } }
        @keyframes w10lqf-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
        @keyframes w10lqf-drift { from { transform: translateX(0); } to { transform: translateX(-500px); } }
        @keyframes w10lqf-bubble { 0% { opacity: 0; transform: translateY(0); } 15% { opacity: 0.8; } 85% { opacity: 0.6; } 100% { opacity: 0; transform: translateY(-120px); } }
        .w10lqf[data-paused="true"] .w10lqf-bob, .w10lqf[data-paused="true"] .w10lqf-front, .w10lqf[data-paused="true"] .w10lqf-back, .w10lqf[data-paused="true"] .w10lqf-bubble { animation-play-state: paused; }
        @media (prefers-reduced-motion: reduce) {
          .w10lqf-rise { animation: none; transform: translateY(var(--w10lqf-level)); }
          .w10lqf-bob, .w10lqf-front, .w10lqf-back, .w10lqf-bubble { animation: none; }
        }
      `}</style>
      <div className="mx-auto max-w-5xl text-center">
        <p className="text-xs font-semibold uppercase tracking-[0.3em] text-[#7a4a3a]">Tidewell refill stations</p>
        <h1 className="mt-6">
          <span className="sr-only">Refill</span>
          <svg aria-hidden="true" viewBox="0 0 1000 300" className="mx-auto block h-auto w-full max-w-4xl">
            <defs>
              <clipPath id={clip}>
                <text x="500" y="262" textAnchor="middle" textLength="960" lengthAdjust="spacingAndGlyphs" fontSize="270" fontWeight="900" fontFamily="ui-sans-serif, system-ui, Arial, sans-serif">{WORD}</text>
              </clipPath>
            </defs>
            <text x="500" y="262" textAnchor="middle" textLength="960" lengthAdjust="spacingAndGlyphs" fontSize="270" fontWeight="900" fontFamily="ui-sans-serif, system-ui, Arial, sans-serif" fill="#fdf3ea" fillOpacity="0.55">{WORD}</text>
            <g clipPath={`url(#${clip})`}>
              <g className="w10lqf-rise">
                <g className="w10lqf-bob">
                  <g transform="translate(0 270)">
                    <path className="w10lqf-back" fill="var(--w10lqf-light)" d="M0 12 Q125 -10 250 12 T500 12 T750 12 T1000 12 T1250 12 T1500 12 T1750 12 T2000 12 V400 H0 Z" />
                    <path className="w10lqf-front" fill="var(--w10lqf-deep)" d="M0 22 Q125 4 250 22 T500 22 T750 22 T1000 22 T1250 22 T1500 22 T1750 22 T2000 22 V400 H0 Z" />
                    <circle className="w10lqf-bubble" cx="180" cy="200" r="6" fill="#e8fbf7" style={{ animationDelay: "0.2s" }} />
                    <circle className="w10lqf-bubble" cx="430" cy="210" r="4" fill="#e8fbf7" style={{ animationDelay: "1.4s" }} />
                    <circle className="w10lqf-bubble" cx="610" cy="190" r="7" fill="#e8fbf7" style={{ animationDelay: "2.3s" }} />
                    <circle className="w10lqf-bubble" cx="840" cy="205" r="5" fill="#e8fbf7" style={{ animationDelay: "0.9s" }} />
                  </g>
                </g>
              </g>
            </g>
            <text x="500" y="262" textAnchor="middle" textLength="960" lengthAdjust="spacingAndGlyphs" fontSize="270" fontWeight="900" fontFamily="ui-sans-serif, system-ui, Arial, sans-serif" fill="none" stroke="var(--w10lqf-outline)" strokeWidth="3">{WORD}</text>
          </svg>
        </h1>
        <p className="mx-auto mt-6 max-w-lg text-base leading-relaxed text-[#5a3a2f] sm:text-lg">
          Bring any bottle to a Tidewell tap for filtered water, still or sparkling, chilled and paid by the litre.
        </p>
        <a
          href="#"
          className="mt-8 inline-flex h-12 items-center rounded-full bg-[#1a4f53] px-7 text-sm font-semibold text-white transition hover:bg-[#1d6f73] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1a4f53] focus-visible:ring-offset-2 focus-visible:ring-offset-[#f7dccd]"
        >
          Find a station near you
        </a>
      </div>
    </section>
  );
}
```
