Eén kenmerk in twee helften: een badge, kop en toelichting naast een groot beeld (slot), links of rechts; smal komt het beeld boven de tekst. Het lichtste inhoudsblok van een landingspagina.
Platform
Dit is het begin van iets nieuws
Een klein bedrijf runnen is al zwaar genoeg. Laat verouderde, omslachtige processen los — wij maken handel eenvoudiger en sneller dan ooit.
blocks/feature/feature-split.tsx
/**
* FeatureSplit — één kenmerk in twee helften: links (of rechts) een badge,
* een kop en een toelichting, ernaast een groot beeld (slot). Smal komt
* het beeld boven de tekst. Het lichtste inhoudsblok van een landingspagina.
*
* Geoogst uit 21st.dev Feature with image (tommyjepsen): de shadcn Badge
* (cva) → een pil op --primary, de lege bg-muted-placeholder → `image`-slot,
* container/py-40 → padding-props, lorem → slots. Statisch.
*/
import type * as React from "react";
export interface FeatureSplitProps extends Omit<React.HTMLAttributes<HTMLElement>, "title" | "children"> {
badge?: React.ReactNode;
title: React.ReactNode;
description?: React.ReactNode;
/** Het beeld (img/video/element); vult een 16:9-vlak. */
image?: React.ReactNode;
/** Beeld links (standaard) of rechts van de tekst. */
imageSide?: "left" | "right";
/** Extra inhoud onder de toelichting (bv. een knop). */
action?: React.ReactNode;
}
export function FeatureSplit({ badge, title, description, image, imageSide = "left", action, className, ...rest }: FeatureSplitProps) {
return (
<section {...rest} className={["fp-feature", imageSide === "right" ? "fp-feature--rechts" : "", className].filter(Boolean).join(" ")}>
<div className="fp-feature__beeld">{image}</div>
<div className="fp-feature__tekst">
{badge && <span className="fp-feature__badge">{badge}</span>}
<h2 className="fp-feature__titel">{title}</h2>
{description && <p className="fp-feature__toelichting">{description}</p>}
{action && <div className="fp-feature__actie">{action}</div>}
</div>
</section>
);
}
blocks/feature/feature.css
/** FeatureSplit — importeren in de app-root (registry-site: app/globals.css). */
.fp-feature {
display: flex; flex-direction: column-reverse; gap: 2.5rem; width: 100%; max-width: 72rem; margin: 0 auto; box-sizing: border-box; padding: 3rem 1.5rem;
background: var(--background); color: var(--foreground);
}
@media (min-width: 64rem) {
.fp-feature { flex-direction: row; align-items: center; padding: 5rem 1.5rem; }
.fp-feature--rechts { flex-direction: row-reverse; }
.fp-feature__tekst { padding-left: 5rem; }
.fp-feature--rechts .fp-feature__tekst { padding-left: 0; padding-right: 5rem; }
}
.fp-feature__beeld { flex: 1 1 0; aspect-ratio: 16 / 9; overflow: hidden; border-radius: calc(var(--radius) * 1.5); background: var(--muted); }
.fp-feature__beeld > * { width: 100%; height: 100%; object-fit: cover; display: block; }
.fp-feature__tekst { flex: 1 1 0; display: flex; flex-direction: column; gap: 1rem; align-items: flex-start; }
.fp-feature__badge { display: inline-flex; align-items: center; padding: 0.125rem 0.625rem; border-radius: 999px; font: inherit; font-size: 0.75rem; font-weight: 600; background: var(--primary); color: var(--primary-foreground); }
.fp-feature__titel { margin: 0; max-width: 36rem; font: inherit; font-weight: 400; font-size: clamp(1.5rem, 3.6vw, 3rem); line-height: 1.1; letter-spacing: -0.03em; }
.fp-feature__toelichting { margin: 0; max-width: 28rem; font: inherit; font-size: 1.125rem; line-height: 1.6; letter-spacing: -0.01em; color: var(--muted-foreground); }
.fp-feature__actie { margin-top: 0.5rem; }