Use Case
Build a Pricing Page with React and Tailwind CSS v4
Build a responsive, accessible pricing page with monthly/yearly toggle, three-tier cards, and FAQ section — using Ninna UI components and Tailwind v4.
Pricing page structure
A pricing page needs: a headline, a billing toggle (monthly/yearly), pricing cards with features, and an FAQ section. Use Container for max-width, SimpleGrid for the card layout, and Accordion for the FAQ.
1. Monthly/yearly toggle
Use Switch from @ninna-ui/forms for the billing toggle:
import { Switch } from "@ninna-ui/forms";import { Text, Badge } from "@ninna-ui/primitives";import { useState } from "react";
const [yearly, setYearly] = useState(false);
<div className="flex items-center justify-center gap-3 mb-8"> <Text>Monthly</Text> <Switch checked={yearly} onCheckedChange={setYearly} /> <Text>Yearly <Badge variant="soft" color="success" size="sm">Save 20%</Badge></Text></div>2. Three-tier pricing cards
Use Card from @ninna-ui/data-display with a grid layout:
import { Card } from "@ninna-ui/data-display";import { Button, Heading, Text, Badge } from "@ninna-ui/primitives";import { VStack } from "@ninna-ui/layout";
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> {plans.map((plan) => ( <Card key={plan.name} className={`p-8 ${plan.popular ? "border-primary ring-2 ring-primary/20" : ""}`}> <VStack gap="4"> {plan.popular && <Badge variant="solid" color="primary">Most Popular</Badge>} <Heading as="h3" size="xl">{plan.name}</Heading> <Text size="3xl" weight="bold">${yearly ? plan.yearly : plan.monthly}<span className="text-base font-normal text-base-content/60">/mo</span></Text> <Button color={plan.popular ? "primary" : "outline"} fullWidth>Get Started</Button> </VStack> </Card> ))}</div>3. FAQ with structured data
Use Accordion from @ninna-ui/navigation and inject FAQPage JSON-LD schema for Google rich results:
import { Accordion } from "@ninna-ui/navigation";import { buildFAQPageJsonLd } from "~/utils/structuredData";
<Accordion type="single" collapsible> <Accordion.Item value="q1"> <Accordion.Trigger>Can I change plans anytime?</Accordion.Trigger> <Accordion.Content>Yes, upgrade or downgrade at any time.</Accordion.Content> </Accordion.Item></Accordion>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: buildFAQPageJsonLd(faqs) }} />