Features 2
Features 2 is a React and Tailwind CSS layout component from SmoothUI, licensed MIT. Copy it and paste it into your project.
SmoothUI
MIT
layout
What it is
Features 2 is a React and Tailwind CSS layout component from SmoothUI, licensed MIT. Copy it and paste it into your project.
How to use it
Open it in the catalogue, press copy, and paste it into your project. The prompt you copy carries the code and the rules that tell your agent to reproduce it without changing anything.
Five free copies a month. No card.
Needs
npm i motion
Licence
This component comes from SmoothUI and is redistributed under the MIT licence, which permits commercial use. The copyright notice travels with the code.
Features 2
"use client";
import { cn } from "@/lib/utils";
import { motion, useReducedMotion } from "motion/react";
const SPRING = {
bounce: 0.1,
duration: 0.25,
type: "spring" as const,
};
const features = [
{
accent: true,
description:
"Real-time analytics dashboard with customizable metrics and beautiful visualizations.",
span: "col-span-2 row-span-2",
title: "Smart Analytics",
// The lead cell of a bento is two columns by two rows. Without something to
// look at, that is a quarter of the section spent on two lines of text.
visual: "analytics" as const,
},
{
description:
"Work together in real-time with built-in commenting and sharing.",
span: "col-span-1",
title: "Team Collaboration",
},
{
description: "RESTful API with comprehensive documentation and SDKs.",
span: "col-span-1",
title: "API First",
},
{
description: "Lightning-fast delivery from edge locations worldwide.",
span: "col-span-1",
title: "Global CDN",
},
{
description:
"Enterprise-grade security with SOC 2 compliance and encryption.",
span: "col-span-1",
title: "Security",
},
];
/** Bars of a plausible-looking week. Fixed, so the panel never reflows. */
const SERIES = [
{ id: "w1", value: 38 },
{ id: "w2", value: 52 },
{ id: "w3", value: 44 },
{ id: "w4", value: 66 },
{ id: "w5", value: 58 },
{ id: "w6", value: 74 },
{ id: "w7", value: 62 },
{ id: "w8", value: 88 },
{ id: "w9", value: 71 },
{ id: "w10", value: 96 },
{ id: "w11", value: 84 },
{ id: "w12", value: 100 },
];
const PEAK_ID = "w12";
const BAR_STAGGER = 0.03;
/**
* A small analytics panel for the bento's lead cell.
*
* Every element is real markup on the page's own tokens, so it follows the
* theme into dark mode and stays sharp at any pixel density — and the bars can
* grow on entry, which is the point of the library it ships with.
*/
const AnalyticsPanel = () => {
const shouldReduceMotion = useReducedMotion();
return (
<div className="flex h-full flex-col gap-4 rounded-xl border bg-background p-5">
<div className="flex items-baseline justify-between gap-3">
<div>
<p className="text-foreground/60 text-xs">Revenue this month</p>
<p className="font-semibold text-2xl text-foreground tabular-nums">
$48,219
</p>
</div>
<span className="rounded-full bg-foreground/5 px-2 py-0.5 font-medium text-foreground/70 text-xs tabular-nums">
+12.4%
</span>
</div>
<div
aria-hidden="true"
className="flex min-h-0 flex-1 items-end gap-1.5 sm:gap-2"
>
{SERIES.map(({ id, value }, index) => (
<motion.span
className={cn(
"flex-1 origin-bottom rounded-t-sm",
id === PEAK_ID ? "bg-foreground" : "bg-foreground/15"
)}
initial={shouldReduceMotion ? { scaleY: 1 } : { scaleY: 0 }}
key={id}
style={{ height: `${value}%` }}
transition={
shouldReduceMotion
? { duration: 0 }
: { ...SPRING, delay: index * BAR_STAGGER }
}
viewport={{ margin: "-80px", once: true }}
whileInView={{ scaleY: 1 }}
/>
))}
</div>
</div>
);
};
export function FeaturesBento() {
const shouldReduceMotion = useReducedMotion();
return (
<section aria-labelledby="features-bento-heading">
<div className="py-24 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="mx-auto mb-16 max-w-2xl text-center">
<h2
className="text-balance font-bold text-3xl tracking-tight md:text-4xl"
id="features-bento-heading"
>
Built for modern teams
</h2>
<p className="mt-4 text-foreground/70 text-lg">
A complete platform with everything you need to ship faster.
</p>
</div>
<div className="grid auto-rows-[180px] grid-cols-2 gap-4 md:grid-cols-4">
{features.map((feature, index) => (
<motion.div
className={cn(
"flex flex-col justify-end overflow-hidden rounded-xl border p-6",
feature.accent
? "bg-foreground/5 ring-1 ring-foreground/10"
: "bg-background",
feature.span
)}
initial={
shouldReduceMotion
? { opacity: 1 }
: { opacity: 0, scale: 0.95 }
}
key={feature.title}
transition={
shouldReduceMotion
? { duration: 0 }
: { ...SPRING, delay: index * 0.05 }
}
viewport={{ margin: "-100px", once: true }}
whileInView={
shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1 }
}
>
{feature.visual === "analytics" && (
// Drawn, not photographed. A screenshot would be fixed to one
// theme, blur on a retina screen and weigh more than the whole
// block; markup inherits the page's colours and stays sharp.
<div className="-mx-6 -mt-6 mb-4 min-h-0 flex-1 overflow-hidden">
<AnalyticsPanel />
</div>
)}
<h3 className="mb-1 font-semibold text-foreground">
{feature.title}
</h3>
<p className="text-foreground/70 text-sm leading-relaxed">
{feature.description}
</p>
</motion.div>
))}
</div>
</div>
</div>
</section>
);
}
export default FeaturesBento;