Skip to content

Load Rise

A block that rises into place as the page paints, in plain CSS, before any script has loaded.

$npx shadcn@latest add https://framebrick.co/r/load-rise.json

From the Semono template, see it in context.

Photography studio

Work that earns its place on the page

It starts with the first paint, before any script has loaded.

Installation

$ npx shadcn@latest add https://framebrick.co/r/load-rise.json

Usage

import { LoadRise } from "@/components/ui/load-rise";

<LoadRise as="p" delay={0.1}>Photography studio</LoadRise>
<LoadRise as="h1" delay={0.2} className="text-5xl font-semibold">Work that earns its place on the page</LoadRise>
<LoadRise as="p" delay={0.4}>A studio for brands that would rather be useful than loud.</LoadRise>
<LoadRise delay={0.5} className="flex gap-3">…buttons…</LoadRise>

Props

PropTypeDefaultDescription
as"div" | "section" | "header" | "h1" | "h2" | "h3" | "p" | "span" | "ul" | "li" | "figure" | "nav""div"The element to render.
delaynumber0Seconds before it starts. A hero staggers its parts 0.1, 0.2, 0.4 and 0.5 s, as Semono's does.
distancenumber60How far it rises, in px.
classNamestring—Classes for the element.
  • It is plain CSS, so it starts with the first paint, before any script has loaded, and a page without scripts shows its content. text-appear and scroll-reveal start when the page hydrates and their content waits at opacity 0 until then: use this for what is on screen as the page opens, and those for what comes into view later. Do not wrap one in the other.
  • Spring E (stiffness 250, damping 55, mass 2.9: about a second) as a 29-stop linear() curve measured on Framer, over 960 ms — within 1% of what tools/ui/spring-curve.mjs makes from the same physics. A browser without linear() gets cubic-bezier(0.22, 1, 0.36, 1) over the same time.
  • It starts from opacity 0.001 and 60 px lower (Framer's 0.001 keeps the block in the render tree). animation-fill-mode backwards holds that first frame during the delay; afterwards the block is exactly as styled.
  • Reduced motion: the same fade without the rise. Print: no animation, so a printed page is never half drawn.
  • The rules are one <style> that React 19 moves to the head once however many blocks use it (href and precedence). With React 18 each block repeats the same few lines.

AI prompt

Paste into v0, Lovable, Bolt or Claude to rebuild this component in your own project.

Create a React + Tailwind CSS component called LoadRise — plain CSS, no JavaScript and no animation library, so it also works in a server component.
- Props: as (div by default; or section, header, h1, h2, h3, p, span, ul, li, figure, nav), delay (seconds), distance (px, default 60), className, children.
- Render <style href="framebrick-load-rise" precedence="default"> holding the rules (React 19 moves it to the head once and dedupes it) and the element with a data-load-rise attribute, style animationDelay set to the delay in seconds and a --load-rise-distance custom property.
- The rules: @keyframes fb-load-rise { from { opacity: .001; transform: translateY(var(--load-rise-distance, 60px)) } } and @keyframes fb-load-fade { from { opacity: .001 } }. [data-load-rise] { animation: fb-load-rise 960ms cubic-bezier(.22,1,.36,1) backwards; animation-timing-function: linear(0,.041,.134,.247,.361,.469,.564,.646,.715,.772,.819,.857,.887,.911,.93,.946,.958,.967,.974,.98,.984,.988,.991,.993,.994,.996,.997,.997,1) } — the list is a spring (stiffness 250, damping 55, mass 2.9) sampled at 29 stops, on its own line so a browser without linear() ignores it and keeps the cubic-bezier. Under prefers-reduced-motion: reduce use animation-name fb-load-fade; under print use animation: none.

Be the first to know

Get new templates and components first

One short email when we release a template or a free component. No spam — unsubscribe anytime.

We use your email only for Framebrick updates. Privacy policy