Every item is $19. Or get all items for $259, paid once.

Get all items
mebius.design
mebius.design

POS dashboard in React: the screens, the numbers and a starting kit

A point-of-sale dashboard has two halves: a fast sale screen at the counter and a back office for everything else, meaning the sales overview, orders and refunds, products and stock, staff and reports. Its home screen answers four questions: how much we sold, how many orders, the average order and the margin. Relivo is a POS dashboard UI kit from mebius.design with Figma screens for cafés and retail and React + Tailwind code for shadcn.

6 min readUpdated Nov 8, 2026React + Tailwind

The screens a POS needs

  • Sale: a product grid with categories and search, the cart with modifiers and discounts, then payment by card, cash or QR with change due and a receipt.
  • Orders: today’s and past orders with their status, and refunds that go back to the payment method.
  • Products and inventory: prices, variants, stock per outlet and a par level that raises an alert.
  • Staff: roles, PINs and shifts, so every sale has a cashier.
  • Reports: sales by day, product, category, payment method and cashier.
  • Settings: outlets, taxes, receipt layout and payment methods.

The numbers on the overview

Compute them from completed sales, net of refunds.

  • Gross sales: the total of completed orders in the period.
  • Orders: their count. Leave refunded orders out of both.
  • Average order value: gross sales divided by orders.
  • Gross margin: (sales minus the cost of the goods sold) divided by sales.
  • Payment mix: sales per payment method, as a donut.
  • Stock alerts: products at or under their par level, out of stock first.

Show each one against the previous period of the same length, so a Monday isn’t compared with a Saturday.


Start from Relivo

Figma screens plus React + Tailwind code for shadcn.

Relivo covers checkout, orders, inventory, staff and reports in Figma, in light and dark. Its code is a set of components (tables, charts, date pickers, dialogs…) and blocks; the store’s home overview is one block, metrics-dashboard, with the sidebar, KPI cards, the revenue trend, the payment mix, recent orders, top products and stock alerts. Screens without a block, like the sale screen, you build from the components with the Figma frame next to you.

Terminal
npx shadcn@latest add @mebius/relivo-theme
npx shadcn@latest add @mebius/relivo-metrics-dashboard --overwrite

This needs the @mebius registry in components.json (setup) and an account that owns Relivo.


Wire the overview to your sales

The block takes ready-formatted values, so compute the numbers on the server and pass them in. A sketch with completed sales for the period:

components/store-overview.tsx
"use client"

import { BanknoteIcon, ReceiptIcon, ShoppingCartIcon, TrendingUpIcon } from "lucide-react"

import { MetricsDashboard, type DashboardKpi } from "@/components/metrics-dashboard"
import type { DonutChartDatum } from "@/components/ui/donut-chart"

type Sale = { total: number; cost: number; method: "card" | "cash" | "qris"; refunded: boolean }

const money = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })

function overview(sales: Sale[]) {
  const done = sales.filter((sale) => !sale.refunded)
  const gross = done.reduce((sum, sale) => sum + sale.total, 0)
  const cost = done.reduce((sum, sale) => sum + sale.cost, 0)
  const kpis: DashboardKpi[] = [
    { label: "Gross Sales", value: money.format(gross), icon: <BanknoteIcon aria-hidden /> },
    { label: "Orders", value: done.length.toLocaleString("en-US"), icon: <ReceiptIcon aria-hidden /> },
    { label: "Avg. Order Value", value: money.format(done.length ? gross / done.length : 0), icon: <ShoppingCartIcon aria-hidden /> },
    { label: "Gross Margin", value: gross ? `${(((gross - cost) / gross) * 100).toFixed(1)}%` : "–", icon: <TrendingUpIcon aria-hidden /> },
  ]
  const payments: DonutChartDatum[] = (["card", "qris", "cash"] as const).map((method) => ({
    key: method,
    label: method === "qris" ? "QRIS" : method[0].toUpperCase() + method.slice(1),
    value: done.filter((sale) => sale.method === method).reduce((sum, sale) => sum + sale.total, 0),
  }))
  return { kpis, payments }
}

export function StoreOverview({ sales, outlet }: { sales: Sale[]; outlet: string }) {
  const { kpis, payments } = overview(sales)
  return (
    <MetricsDashboard
      className="h-full"
      meta={[outlet, "Today"]}
      kpis={kpis}
      payments={payments}
      onNewSale={() => window.location.assign("/pos")}
    />
  )
}

The revenue trend, recent orders, top products and alerts take your rows the same way (revenue, orders, products, alerts), and onFiltersChange reports the period, store, channel and comparison the toolbar picks so you can refetch.


Item pages, kits and guides this guide uses.