All components

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.

Open in the catalogue

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

index.tsx
"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;

Similar components