Alder Row, Riverside
Twenty-four homes in a restored brick warehouse and a new courtyard wing. Leave your details and Laura Marling and the sales team will send the brochure, the price list and the first viewing dates before they go public.
No calls unless you ask for one. One email when the price list is ready, one when viewings open.

A development hero split in two: eyebrow, large sans headline, intro and a privacy line on the left; on the right a tall 4:5 photograph that is unveiled from the top once loaded and drifts against the scroll, with a compact register form (first name, email, bedroom pills writing to a hidden field, a submit pill) laid over its bottom edge on desktop, submitting as a GET request with configurable parameter names.
A development hero split in two: eyebrow, large sans headline, intro and a short privacy line on the left; on the right a tall 4:5 photograph that is unveiled from the top once it has loaded and drifts slowly against the scroll, with a compact register form (first name, email, bedroom pills that write to a hidden field, and a submit pill) laid over the photograph's bottom edge on desktop. The form is a plain GET form with configurable parameter names, so it works against any listings or CRM endpoint without JavaScript.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://beste.dev/r/realestate13?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/realestate13?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/realestate13.tsx plus the badge24 rule eyebrow, the button25 pill behind the submit button, and the shadcn/ui button and input primitives they build on.
The installed file exports realestate13Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Realestate13, realestate13Demo } from "@/components/beste/block/realestate13";
export default function Page() {
return <Realestate13 {...realestate13Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Realestate13 } from "@/components/beste/block/realestate13";
export default function Page() {
return (
<Realestate13
eyebrow="Alder Row, Riverside"
heading="Register for the first viewings this spring."
description="Twenty-four homes in a restored brick warehouse and a new courtyard wing. Leave your details and the sales team will send the brochure and the first viewing dates."
image={{
src: "https://oud.pics/b/realestate/alder-courtyard-kitchen.webp",
alt: "An open kitchen with oak cabinets and a pale stone island",
}}
form={{
action: "/register",
params: { firstName: "first_name", email: "email", bedrooms: "bedrooms" },
bedrooms: ["2", "3", "Penthouse"],
selected: "2",
}}
labels={{
title: "Register your interest",
firstName: "First name",
firstNamePlaceholder: "Your first name",
email: "Email",
emailPlaceholder: "[email protected]",
bedrooms: "Bedrooms",
submit: "Register",
}}
note="One email when the price list is ready, one when viewings open."
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Short line above the headline, rendered through badge24 on mount. |
heading | string | – | The headline, rendered as an h1. |
description | string | – | Intro paragraph under the headline. |
image | { src: string; alt: string } | – | The tall 4:5 photograph on the right; the form overlaps its bottom edge from the md breakpoint. |
form | RegisterForm | – | The GET form: its action, the parameter names, the bedroom options and the one selected on load. |
labels | Labels | {} | Form title, field labels, placeholders and the submit label. |
note | string | – | Short privacy line at the foot of the text column. |
className | string | – | Extra classes merged onto the section. |
type RegisterForm = {
action: string;
params?: { firstName?: string; email?: string; bedrooms?: string };
bedrooms?: string[];
selected?: string;
};
type Labels = {
title?: string;
firstName?: string;
firstNamePlaceholder?: string;
email?: string;
emailPlaceholder?: string;
bedrooms?: string;
submit?: string;
};load event (or the complete flag when cached): the frame stays clipped to zero height until then, opens from the top over 1.6 seconds while the image settles from a 1.18 to a 1.12 scale, and drifts from -6% to 6% as the frame crosses the viewport.aria-pressed buttons; the chosen value is written to a hidden input named by form.params.bedrooms, so the choice travels with the GET request like any other field. The first option is selected when form.selected is omitted.required attribute, so the browser blocks an empty submit without any script. Parameter names fall back to first_name, email and bedrooms when params is omitted.md it sits under the photograph with no panel padding, so the layout stays a single column.prefers-reduced-motion every entrance, the clip reveal and the parallax are disabled and the hero renders in its final state.Wiring the form up
The form submits as a GET request to the action you pass, with the field names from params. To validate on the client and handle submission in React instead, see React Hook Form, TanStack Form, and Formisch.