# Widgets 22

> Widgets 22 variant for block.

A shadcn/ui block from the [@uiable](https://uiable.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/uiable/block-widgets-22).

- Page, with a live preview: https://shadcn.exchange/r/uiable/block-widgets-22
- Screenshot: https://shadcn.exchange/shot/uiable/block-widgets-22/light.png
- Registry item: https://uiable.com/r/block-widgets-22.json
- Categories: widgets
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/uiable/block-widgets-22.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `@uiable/button`, `@uiable/card`, `@uiable/dropdown-menu`, `@uiable/tabs`

## Files

### `src/components/uiable/blocks/widgets/widgets-22/widgets-22.tsx`

```tsx
"use client"

// shadcn
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

// assets
import {
  ArrowLeftRight,
  BellRing,
  Download,
  MoreVertical,
  Plus,
  RefreshCcw,
  TrendingDown,
  TrendingUp,
} from "lucide-react"

//  ------------------------------ | WIDGETS 22 | ------------------------------  //

type AvatarColor = "teal" | "amber" | "blue" | "rose" | "violet"

// full class strings so Tailwind can statically detect them
const avatarStyles: Record<AvatarColor, string> = {
  teal: "bg-teal-600/10 text-teal-600",
  amber: "bg-amber-500/10 text-amber-500",
  blue: "bg-blue-500/10 text-blue-500",
  rose: "bg-rose-500/10 text-rose-500",
  violet: "bg-violet-500/10 text-violet-500",
}

type Trend = "up" | "down" | "flat"
type Status = "success" | "pending"

type Transaction = {
  name: string
  meta: string
  initials: string
  color: AvatarColor
  amount: string
  delta: string
  trend: Trend
  status: Status
}

const transactions: Transaction[] = [
  {
    name: "Uber",
    meta: "08:40 pm",
    initials: "U",
    color: "blue",
    amount: "+210,000",
    delta: "10.6%",
    trend: "up",
    status: "success",
  },
  {
    name: "Ola Cabs",
    meta: "07:40 pm",
    initials: "OC",
    color: "amber",
    amount: "+210,000",
    delta: "10.6%",
    trend: "up",
    status: "success",
  },
  {
    name: "Apple Inc.",
    meta: "#ABLE-PRO-T00232",
    initials: "AI",
    color: "rose",
    amount: "$210,000",
    delta: "10.6%",
    trend: "down",
    status: "pending",
  },
  {
    name: "Spotify Music",
    meta: "#ABLE-PRO-T10232",
    initials: "SM",
    color: "teal",
    amount: "- 10,000",
    delta: "30.6%",
    trend: "up",
    status: "success",
  },
  {
    name: "Medium",
    meta: "06:30 pm",
    initials: "MD",
    color: "violet",
    amount: "-26",
    delta: "5%",
    trend: "flat",
    status: "pending",
  },
]

const tabs: { value: string; label: string; items: Transaction[] }[] = [
  {
    value: "all",
    label: "All Transaction",
    items: transactions,
  },
  {
    value: "success",
    label: "Success",
    items: transactions.filter((t) => t.status === "success"),
  },
  {
    value: "pending",
    label: "Pending",
    items: transactions.filter((t) => t.status === "pending"),
  },
]

const transactionActions = [
  { label: "View all transactions", icon: ArrowLeftRight },
  { label: "Export report", icon: Download },
  { label: "Set reminders", icon: BellRing },
  { label: "Refresh list", icon: RefreshCcw },
]

// tinted delta pill per trend direction
const trendStyles: Record<Trend, string> = {
  up: "bg-teal-500/10 text-teal-600 dark:text-teal-400",
  down: "bg-rose-500/10 text-rose-600 dark:text-rose-400",
  flat: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
}

const trendIcons: Record<Trend, React.ComponentType<{ className?: string }>> = {
  up: TrendingUp,
  down: TrendingDown,
  flat: ArrowLeftRight,
}

function TransactionRow({ txn }: { txn: Transaction }) {
  const TrendIcon = trendIcons[txn.trend]

  return (
    <li className="group flex items-center justify-between gap-3 border-b border-border/50 py-3 transition-colors last:border-b-0 hover:bg-muted/40">
      <div className="flex min-w-0 items-center gap-3">
        <span
          className={`flex size-10 shrink-0 items-center justify-center rounded-xl text-xs font-semibold ring-1 ring-border/50 ring-inset ${avatarStyles[txn.color]}`}
        >
          {txn.initials}
        </span>
        <div className="min-w-0 space-y-0.5">
          <p className="truncate text-sm font-semibold text-foreground">
            {txn.name}
          </p>
          <p className="truncate text-xs text-muted-foreground">{txn.meta}</p>
        </div>
      </div>

      <div className="flex shrink-0 flex-col items-end gap-1">
        <span className="text-sm font-semibold text-foreground tabular-nums">
          {txn.amount}
        </span>
        <span
          className={`inline-flex items-center gap-0.5 rounded-full px-1.5 py-0.5 text-xs font-semibold tabular-nums ${trendStyles[txn.trend]}`}
        >
          <TrendIcon className="size-3" />
          {txn.delta}
        </span>
      </div>
    </li>
  )
}

export default function Widgets22() {
  return (
    <div className="w-full min-w-0">
      <Card className="relative mb-0 overflow-hidden rounded-2xl border-border/60 shadow-sm transition-shadow hover:shadow-md">
        {/* accent glow */}
        <span
          aria-hidden
          className="pointer-events-none absolute -top-12 -right-10 size-32 rounded-full bg-teal-500 opacity-20 blur-3xl"
        />

        <CardContent className="relative flex flex-col gap-4 p-6">
          <div className="flex items-start justify-between gap-3">
            <h3 className="text-lg font-semibold tracking-tight text-foreground">
              Transactions
            </h3>
            <DropdownMenu>
              <DropdownMenuTrigger
                render={
                  <Button
                    variant="ghost"
                    size="icon-sm"
                    className="shrink-0 text-muted-foreground hover:bg-muted/70 hover:text-foreground"
                    aria-label="More options"
                  />
                }
              >
                <MoreVertical className="size-4" />
              </DropdownMenuTrigger>
              <DropdownMenuContent align="end" className="w-52 p-1.5">
                {transactionActions.map(({ icon: Icon, label }) => (
                  <DropdownMenuItem
                    key={label}
                    className="gap-2 rounded-lg px-2 py-1.5 text-sm"
                    onSelect={(event) => event.preventDefault()}
                  >
                    <Icon className="size-4 text-muted-foreground" />
                    <span>{label}</span>
                  </DropdownMenuItem>
                ))}
                <DropdownMenuSeparator />
                <DropdownMenuItem
                  className="gap-2 rounded-lg px-2 py-1.5 text-sm"
                  onSelect={(event) => event.preventDefault()}
                >
                  <Plus className="size-4 text-muted-foreground" />
                  <span>Create new transaction</span>
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>

          <Tabs defaultValue="all" className="gap-4">
            <TabsList
              variant="line"
              className="h-auto w-full justify-start gap-6 rounded-none border-b border-border/60 p-0 pb-1.5"
            >
              {tabs.map((tab) => (
                <TabsTrigger
                  key={tab.value}
                  value={tab.value}
                  className="flex-none px-0 pb-2 text-sm font-medium group-data-[variant=line]/tabs-list:data-active:text-teal-600 data-active:after:bg-teal-600 group-data-[variant=line]/tabs-list:data-active:hover:text-teal-600"
                >
                  {tab.label}
                </TabsTrigger>
              ))}
            </TabsList>

            {tabs.map((tab) => (
              <TabsContent key={tab.value} value={tab.value}>
                <ul className="flex flex-col">
                  {tab.items.map((txn, index) => (
                    <TransactionRow key={`${txn.name}-${index}`} txn={txn} />
                  ))}
                </ul>
              </TabsContent>
            ))}
          </Tabs>

          <div className="grid grid-cols-1 gap-3 pt-1 sm:grid-cols-2">
            <Button
              variant="outline"
              className="w-full border-teal-600/30 text-teal-600 hover:bg-teal-500/10 hover:text-teal-700 dark:text-teal-400"
            >
              View all Transaction History
            </Button>
            <Button className="w-full bg-teal-600 text-white hover:bg-teal-700">
              Create new Transaction
            </Button>
          </div>
        </CardContent>
      </Card>
    </div>
  )
}
```
