Skip to content

Instantly share code, notes, and snippets.

@nimone
Created July 6, 2023 07:31
Show Gist options
  • Save nimone/373fc7d2184a1534c2a91bc4b52ff235 to your computer and use it in GitHub Desktop.
Save nimone/373fc7d2184a1534c2a91bc4b52ff235 to your computer and use it in GitHub Desktop.
Build a Plan Selection Page with Custom Radio Component using React and Tailwind CSS
import { useState } from "react"
import Radio, { RadioGroup } from "./components/Radio"
import { BadgePercent, Sparkle, Gem, Crown, ArrowRight } from "lucide-react"
export default function App() {
const [plan, setPlan] = useState("")
return (
<main className="min-h-screen flex flex-col items-center justify-center">
<h2 className="text-2xl font-bold tracking-tight">Choose Your Plan</h2>
<hr className="my-3 w-56" />
<RadioGroup value={plan} onChange={(e) => setPlan(e.target.value)}>
<div className="flex gap-4 justify-center flex-col">
<Radio value="free">
<Plan
icon={<BadgePercent />}
title="Free"
features={["SD (480p)", "Mobile", "Ads"]}
price={0}
/>
</Radio>
<Radio value="basic">
<Plan
icon={<Sparkle />}
title="Basic"
features={["HD (720p)", "1 Device"]}
price={4.99}
/>
</Radio>
<Radio value="standard">
<Plan
icon={<Gem />}
title="Standard"
features={["Full HD (1080p)", "2 Devices"]}
price={9.99}
/>
</Radio>
<Radio value="premium">
<Plan
icon={<Crown />}
title="Premium"
features={["Ultra HD (4K) + HDR", "4 Devices"]}
price={14.99}
/>
</Radio>
</div>
</RadioGroup>
<hr className="my-3 w-56" />
<button
className={`
flex gap-4 items-center px-6 py-3 rounded-lg
bg-violet-800 hover:bg-violet-700
font-semibold text-lg text-white
`}
>
Proceed with {plan} plan
<ArrowRight />
</button>
</main>
)
}
function Plan({ icon, title, features, price }) {
return (
<div className="flex gap-4 items-center">
{icon}
<div>
<h3 className="text-lg font-semibold">{title}</h3>
<p className="text-sm">{features.join(" · ")}</p>
</div>
<span className="ml-auto font-medium">${price}</span>
</div>
)
}
import { useContext, createContext } from "react"
const RadioContext = createContext()
export default function Radio({ children, ...props }) {
const { value, onChange } = useContext(RadioContext)
return (
<label
className={`
px-6 py-4 shadow rounded-lg cursor-pointer
transition-all ${
value === props.value
? "bg-gradient-to-t from-violet-200 to-violet-100 text-violet-800 shadow-violet-500 scale-105"
: "bg-white hover:shadow-md shadow-gray-300"
}
`}
>
<input
type="radio"
className="hidden"
checked={value === props.value}
onChange={onChange}
{...props}
/>
{children}
</label>
)
}
export function RadioGroup({ value, onChange, children }) {
return (
<RadioContext.Provider value={{ value, onChange }}>
{children}
</RadioContext.Provider>
)
}
@Stiler45
Copy link

Stiler45 commented Jun 3, 2024

Thank you! Helped me very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment