Back to Code Bytes
2 min read
Panel Reveal

Description

Panel Reveal is designed for content that expands within an existing card or section, such as a detail panel or a collapsible block of form fields. The panel travels a short distance on the Y axis while fading in and clearing a soft blur, so even a half-height travel reads as a complete open. Wrap it in a container with overflow: hidden to clip the closed state.

Example

Shipping address

123 Main Street, Springfield

CSS

:root {
  --panel-open-dur: 400ms;
  --panel-close-dur: 350ms;
  --panel-translate-y: 100px;
  --panel-blur: 2px;
  --panel-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.t-panel-slide {
  transform: translateY(var(--panel-translate-y));
  opacity: 0;
  filter: blur(var(--panel-blur));
  pointer-events: none;
  transition:
    transform var(--panel-close-dur) var(--panel-ease),
    opacity var(--panel-close-dur) var(--panel-ease),
    filter var(--panel-close-dur) var(--panel-ease);
  will-change: transform, opacity, filter;
}
.t-panel-slide[data-open="true"] {
  transform: translateY(0);
  opacity: 1;
  filter: blur(0);
  pointer-events: auto;
  transition:
    transform var(--panel-open-dur) var(--panel-ease),
    opacity var(--panel-open-dur) var(--panel-ease),
    filter var(--panel-open-dur) var(--panel-ease);
}

@media (prefers-reduced-motion: reduce) {
  .t-panel-slide {
    transition: none !important;
  }
}

React

import { useState } from "react";
import "./panel-reveal.css"; // paste the CSS above

export function PanelReveal() {
  const [open, setOpen] = useState(false);
  return (
    <div style={{ overflow: "hidden" }}>
      <div
        className="t-panel-slide"
        data-open={open ? "true" : "false"}
        style={{ "--panel-translate-y": "64px" } as React.CSSProperties}
      >
        <p>Shipping address</p>
        <p>123 Main Street, Springfield</p>
      </div>
      <button onClick={() => setOpen((v) => !v)}>
        {open ? "Close panel" : "Open panel"}
      </button>
    </div>
  );
}

Variables

VariableDefaultNotes
--panel-open-dur400mssourced from --p3-open-dur
--panel-close-dur350mssourced from --p3-close-dur
--panel-translate-y100pxsourced from --p3-translate-y
--panel-blur2pxsourced from --p3-blur
--panel-easecubic-bezier(0.22, 1, 0.36, 1)sourced from --p3-ease

Credit

Adapted from Panel Reveal on transitions.dev by Jakub Antalik. Original source: github.com/Jakubantalik/transitions.dev.