# NiceUI — full source
> NiceUI is a free, open-source library of premium React and Tailwind CSS components, blocks and templates. Copy the code or install with the shadcn CLI. MIT licensed, no account required.
---
## Avatar Group
Overlapping avatars with initials fallback, hover lift and a +N overflow counter.
URL: https://niceui.dev/components/avatar-group
Install: `npx shadcn@latest add https://niceui.dev/r/avatar-group.json`
File: `components/ui/avatar-group.tsx`
```tsx
import * as React from "react";
export interface AvatarGroupProps {
people: { name: string; src?: string }[];
max?: number;
className?: string;
}
const initials = (name: string) =>
name
.split(" ")
.map((part) => part[0])
.join("")
.slice(0, 2)
.toUpperCase();
export function AvatarGroup({ people, max = 4, className = "" }: AvatarGroupProps) {
const shown = people.slice(0, max);
const rest = people.length - shown.length;
return (
{shown.map((person, i) => (
{person.src ?
: initials(person.name)}
))}
{rest > 0 && (
+{rest}
)}
);
}
```
Usage:
```tsx
import { AvatarGroup } from "@/components/ui/avatar-group";
const people = ["Ada King", "Mia Jones", "Raj Shah", "Leo Park", "Noa Ito", "Sam Lee"];
export default function Example() {
return ({ name }))} max={4} />;
}
```
---
## Badge
Compact status labels in neutral, sky and outline variants, with an optional glowing status dot.
URL: https://niceui.dev/components/badge
Install: `npx shadcn@latest add https://niceui.dev/r/badge.json`
File: `components/ui/badge.tsx`
```tsx
import * as React from "react";
type Variant = "neutral" | "sky" | "outline";
const variants: Record = {
neutral: "bg-white/[.06] text-zinc-300",
sky: "border border-sky-300/30 bg-sky-300/10 text-sky-300",
outline: "border border-white/15 text-zinc-400",
};
export interface BadgeProps extends React.HTMLAttributes {
variant?: Variant;
dot?: boolean;
}
export function Badge({ variant = "neutral", dot = false, className = "", children, ...props }: BadgeProps) {
return (
{dot && }
{children}
);
}
```
Usage:
```tsx
import { Badge } from "@/components/ui/badge";
export default function Example() {
return (
Live
Draft
Archived
);
}
```
---
## Button
A pill-shaped button with primary, outline and ghost variants in three sizes. Accessible focus ring, forwarded ref.
URL: https://niceui.dev/components/button
Install: `npx shadcn@latest add https://niceui.dev/r/button.json`
File: `components/ui/button.tsx`
```tsx
import * as React from "react";
type Variant = "primary" | "outline" | "ghost";
type Size = "sm" | "md" | "lg";
const variants: Record = {
primary:
"bg-sky-300 text-sky-950 shadow-[0_0_0_1px_rgba(125,211,252,.4),0_8px_32px_-8px_rgba(56,189,248,.6)] hover:bg-sky-200",
outline: "border border-white/15 text-zinc-100 hover:border-white/30 hover:bg-white/[.03]",
ghost: "text-zinc-400 hover:bg-white/5 hover:text-zinc-100",
};
const sizes: Record = {
sm: "h-8 px-3.5 text-xs",
md: "h-10 px-5 text-sm",
lg: "h-12 px-6 text-base",
};
export interface ButtonProps extends React.ButtonHTMLAttributes {
variant?: Variant;
size?: Size;
}
export const Button = React.forwardRef(
({ variant = "primary", size = "md", className = "", ...props }, ref) => (
)
);
Button.displayName = "Button";
```
Usage:
```tsx
import { Button } from "@/components/ui/button";
export default function Example() {
return (
);
}
```
---
## Command Palette
A ⌘K search palette with live filtering, arrow-key navigation and an Enter action per item.
URL: https://niceui.dev/components/command-palette
Install: `npx shadcn@latest add https://niceui.dev/r/command-palette.json`
File: `components/ui/command-palette.tsx`
```tsx
"use client";
import * as React from "react";
export interface CommandItem {
label: string;
hint?: string;
onSelect?: () => void;
}
export interface CommandPaletteProps {
items: CommandItem[];
placeholder?: string;
className?: string;
}
export function CommandPalette({ items, placeholder = "Search…", className = "" }: CommandPaletteProps) {
const [query, setQuery] = React.useState("");
const [active, setActive] = React.useState(0);
const inputRef = React.useRef(null);
const results = items.filter((item) => item.label.toLowerCase().includes(query.toLowerCase()));
React.useEffect(() => setActive(0), [query]);
React.useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
inputRef.current?.focus();
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);
const onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "ArrowDown") {
e.preventDefault();
setActive((i) => Math.min(i + 1, results.length - 1));
} else if (e.key === "ArrowUp") {
e.preventDefault();
setActive((i) => Math.max(i - 1, 0));
} else if (e.key === "Enter") {
results[active]?.onSelect?.();
}
};
return (
{results.length === 0 && - No results
}
{results.map((item, i) => (
- setActive(i)}
onClick={item.onSelect}
className={[
"flex cursor-pointer justify-between rounded-lg px-2.5 py-2 text-[13px] transition-colors",
i === active ? "bg-sky-300/10 text-zinc-100" : "text-zinc-400",
].join(" ")}
>
{item.label}
{item.hint && (
{item.hint}
)}
))}
);
}
```
Usage:
```tsx
import { CommandPalette } from "@/components/ui/command-palette";
export default function Example() {
return (
);
}
```
---
## Floating Input
A text input whose label floats above the value on focus. Pure CSS peer states, no JavaScript needed for the animation.
URL: https://niceui.dev/components/floating-input
Install: `npx shadcn@latest add https://niceui.dev/r/floating-input.json`
File: `components/ui/floating-input.tsx`
```tsx
import * as React from "react";
export interface FloatingInputProps extends Omit, "placeholder"> {
label: string;
}
export const FloatingInput = React.forwardRef(
({ label, id, className = "", ...props }, ref) => {
const autoId = React.useId();
const inputId = id ?? autoId;
return (
);
}
);
FloatingInput.displayName = "FloatingInput";
```
Usage:
```tsx
import { FloatingInput } from "@/components/ui/floating-input";
export default function Example() {
return ;
}
```
---
## Marquee
An infinite, edge-faded horizontal scroller for logos, tags or testimonials. Pauses on hover.
URL: https://niceui.dev/components/marquee
Install: `npx shadcn@latest add https://niceui.dev/r/marquee.json`
File: `components/ui/marquee.tsx`
```tsx
import * as React from "react";
export interface MarqueeProps {
children: React.ReactNode;
duration?: number;
pauseOnHover?: boolean;
className?: string;
}
export function Marquee({ children, duration = 24, pauseOnHover = true, className = "" }: MarqueeProps) {
return (
);
}
```
Usage:
```tsx
import { Marquee } from "@/components/ui/marquee";
const tags = ["Accordion", "Dialog", "Tooltip", "Sidebar", "Command", "Toast"];
export default function Example() {
return (
);
}
```
---
## Segmented Control
A pill tab switcher with a sliding sky indicator that springs between options.
URL: https://niceui.dev/components/segmented-control
Install: `npx shadcn@latest add https://niceui.dev/r/segmented-control.json`
File: `components/ui/segmented-control.tsx`
```tsx
"use client";
import * as React from "react";
export interface SegmentedControlProps {
options: string[];
value?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
className?: string;
}
export function SegmentedControl({
options,
value,
defaultValue,
onValueChange,
className = "",
}: SegmentedControlProps) {
const [inner, setInner] = React.useState(defaultValue ?? options[0]);
const active = value ?? inner;
const refs = React.useRef<(HTMLButtonElement | null)[]>([]);
const [box, setBox] = React.useState({ left: 0, width: 0 });
React.useLayoutEffect(() => {
const el = refs.current[options.indexOf(active)];
if (el) setBox({ left: el.offsetLeft, width: el.offsetWidth });
}, [active, options]);
const select = (option: string) => {
if (value === undefined) setInner(option);
onValueChange?.(option);
};
return (
{options.map((option, i) => (
))}
);
}
```
Usage:
```tsx
import { SegmentedControl } from "@/components/ui/segmented-control";
export default function Example() {
return ;
}
```
---
## Shimmer Button
A dark button with a sweeping sky-blue shimmer and a glowing bottom edge. Zero dependencies, keyframes included.
URL: https://niceui.dev/components/shimmer-button
Install: `npx shadcn@latest add https://niceui.dev/r/shimmer-button.json`
File: `components/ui/shimmer-button.tsx`
```tsx
import * as React from "react";
export interface ShimmerButtonProps extends React.ButtonHTMLAttributes {}
export function ShimmerButton({ children, className = "", ...props }: ShimmerButtonProps) {
return (
);
}
```
Usage:
```tsx
import { ShimmerButton } from "@/components/ui/shimmer-button";
export default function Example() {
return Join the beta;
}
```
---
## Slider
A minimal range slider with a sky fill, soft halo thumb and a live value readout.
URL: https://niceui.dev/components/slider
Install: `npx shadcn@latest add https://niceui.dev/r/slider.json`
File: `components/ui/slider.tsx`
```tsx
"use client";
import * as React from "react";
export interface SliderProps {
label?: string;
min?: number;
max?: number;
step?: number;
defaultValue?: number;
format?: (value: number) => string;
onValueChange?: (value: number) => void;
className?: string;
}
export function Slider({
label,
min = 0,
max = 100,
step = 1,
defaultValue = 50,
format = (v) => String(v),
onValueChange,
className = "",
}: SliderProps) {
const [value, setValue] = React.useState(defaultValue);
const pct = ((value - min) / (max - min)) * 100;
return (
{label && (
{label}
{format(value)}
)}
{
const next = Number(e.target.value);
setValue(next);
onValueChange?.(next);
}}
style={{ background: "linear-gradient(90deg,#7dd3fc " + pct + "%,#1c1e22 " + pct + "%)" }}
className={[
"h-1 w-full cursor-pointer appearance-none rounded-full outline-none",
"[&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full",
"[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-[0_0_0_4px_rgba(125,211,252,.25)]",
"[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-white",
].join(" ")}
/>
);
}
```
Usage:
```tsx
import { Slider } from "@/components/ui/slider";
export default function Example() {
return v + "%"} />;
}
```
---
## Stat Card
A KPI card with label, value, delta and an inline sparkline generated from your data points.
URL: https://niceui.dev/components/stat-card
Install: `npx shadcn@latest add https://niceui.dev/r/stat-card.json`
File: `components/ui/stat-card.tsx`
```tsx
import * as React from "react";
export interface StatCardProps {
label: string;
value: string;
delta?: string;
trend?: number[];
className?: string;
}
function toPath(points: number[], w = 120, h = 32) {
const max = Math.max(...points);
const min = Math.min(...points);
const range = max - min || 1;
return points
.map((p, i) => {
const x = (i / (points.length - 1)) * w;
const y = h - 4 - ((p - min) / range) * (h - 8);
return (i === 0 ? "M" : "L") + x.toFixed(1) + " " + y.toFixed(1);
})
.join(" ");
}
export function StatCard({ label, value, delta, trend, className = "" }: StatCardProps) {
return (
{label}
{delta && {delta}}
{value}
{trend && trend.length > 1 && (
)}
);
}
```
Usage:
```tsx
import { StatCard } from "@/components/ui/stat-card";
export default function Example() {
return (
);
}
```
---
## Switch
An accessible toggle with a springy thumb. Works controlled or uncontrolled and uses role="switch".
URL: https://niceui.dev/components/switch
Install: `npx shadcn@latest add https://niceui.dev/r/switch.json`
File: `components/ui/switch.tsx`
```tsx
"use client";
import * as React from "react";
export interface SwitchProps {
checked?: boolean;
defaultChecked?: boolean;
onCheckedChange?: (checked: boolean) => void;
disabled?: boolean;
label?: string;
className?: string;
}
export function Switch({
checked,
defaultChecked = false,
onCheckedChange,
disabled,
label,
className = "",
}: SwitchProps) {
const [inner, setInner] = React.useState(defaultChecked);
const on = checked ?? inner;
const toggle = () => {
if (checked === undefined) setInner(!on);
onCheckedChange?.(!on);
};
return (
);
}
```
Usage:
```tsx
import { Switch } from "@/components/ui/switch";
export default function Example() {
return (
);
}
```
---
## Hero — Horizon
A cinematic landing hero with serif-italic accent, dual CTAs and the signature glowing horizon arc.
URL: https://niceui.dev/blocks/hero-horizon
Install: `npx shadcn@latest add https://niceui.dev/r/hero-horizon.json`
File: `components/hero-horizon.tsx`
```tsx
import * as React from "react";
export interface HeroHorizonProps {
eyebrow?: string;
title?: string;
accent?: string;
rest?: string;
description?: string;
primary?: { label: string; href: string };
secondary?: { label: string; href: string };
}
export function HeroHorizon({
eyebrow = "Now in public beta",
title = "Ship faster,",
accent = "beautifully",
rest = "built.",
description = "The platform for teams who care about craft. Everything you need to launch, nothing you do not.",
primary = { label: "Get started", href: "#" },
secondary = { label: "Read the docs", href: "#" },
}: HeroHorizonProps) {
return (
{eyebrow}
{title}
{accent} {rest}
{description}
);
}
```
Usage:
```tsx
import { HeroHorizon } from "@/components/hero-horizon";
export default function Page() {
return ;
}
```
---
## Pricing — Minimal
Three-tier pricing with a monthly/yearly toggle, featured plan glow and checkmark feature lists.
URL: https://niceui.dev/blocks/pricing-minimal
Install: `npx shadcn@latest add https://niceui.dev/r/pricing-minimal.json`
File: `components/pricing-minimal.tsx`
```tsx
"use client";
import * as React from "react";
export interface Tier {
name: string;
monthly: number;
yearly: number;
description: string;
features: string[];
cta: string;
featured?: boolean;
}
const defaultTiers: Tier[] = [
{ name: "Starter", monthly: 0, yearly: 0, description: "For side projects.", features: ["3 projects", "Community support", "Basic analytics"], cta: "Start free" },
{ name: "Pro", monthly: 24, yearly: 19, description: "For growing products.", features: ["Unlimited projects", "Priority support", "Advanced analytics", "Custom domains"], cta: "Upgrade to Pro", featured: true },
{ name: "Team", monthly: 59, yearly: 49, description: "For teams at scale.", features: ["Everything in Pro", "SSO and audit log", "Dedicated manager"], cta: "Contact sales" },
];
export function PricingMinimal({ tiers = defaultTiers }: { tiers?: Tier[] }) {
const [yearly, setYearly] = React.useState(true);
return (
Simple, honest pricing.
{["Monthly", "Yearly"].map((label) => {
const on = (label === "Yearly") === yearly;
return (
);
})}
{tiers.map((tier) => (
{tier.name}
{tier.featured && (
Popular
)}
${yearly ? tier.yearly : tier.monthly}
/ mo
{tier.description}
{tier.features.map((feature) => (
-
{feature}
))}
))}
);
}
```
Usage:
```tsx
import { PricingMinimal } from "@/components/pricing-minimal";
export default function Page() {
return ;
}
```