OpenSourceUIOpenSourceUIOpensource UI
GitHub—
  1. Home
  2. Components
  3. Text
  4. Cafe Menu Board
Back to TextComponents / Text

Cafe Menu Board

Free Text React component — CafeMenuBoardCard. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.

Dark chalkboard-style menu with cafe header, item notes, and amber price accents — hospitality and local brand sites.

Preview

Corner & Steam

Small batch · Open till 8

  • Flat White

    Double shot

    ₹180

  • Cold Brew

    ₹210

  • Almond Croissant

    Baked daily

    ₹160

  • Matcha Latte

    ₹220

Setup

How to use

Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.

  1. 1

    Run in your terminal:

    $npm install clsx tailwind-merge lucide-react
  2. 2

    Copy lib/cn.ts below. Skip if you already have cn().

  3. 3

    Copy the code below and create components/text/cafe-menu-board-card.tsx in your project.

  4. 4

    Import and render:

    Example

    import { CafeMenuBoardCard } from "@/components/text/cafe-menu-board-card";

    <CafeMenuBoardCard cafeName="Corner & Steam" items={menuItems} />

lib/cn.ts

1
2
3
4
5
6
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

components/text/cafe-menu-board-card.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"use client";
 
import { forwardRef, type ComponentPropsWithoutRef } from "react";
 
import { cn } from "@/lib/cn";
import { Coffee } from "lucide-react";
 
export type CafeMenuItem = Readonly<{
name: string;
price: string;
note?: string;
}>;
 
export type CafeMenuBoardCardProps = Readonly<
{
cafeName?: string;
tagline?: string;
items?: readonly CafeMenuItem[];
} & ComponentPropsWithoutRef<"div">
>;
 
const DEFAULT_ITEMS: readonly CafeMenuItem[] = [
{ name: "Flat White", price: "₹180", note: "Double shot" },
{ name: "Cold Brew", price: "₹210" },
{ name: "Almond Croissant", price: "₹160", note: "Baked daily" },
{ name: "Matcha Latte", price: "₹220" },
];
 
export const CafeMenuBoardCard = forwardRef<
HTMLDivElement,
CafeMenuBoardCardProps
>(
(
{
className,
cafeName = "Corner & Steam",
tagline = "Small batch · Open till 8",
items = DEFAULT_ITEMS,
...props
},
ref,
) => {
return (
<div
ref={ref}
data-slot="cafe-menu-board-card"
className={cn(
"w-80 overflow-hidden rounded-3xl border border-neutral-800 bg-neutral-950 font-sans text-neutral-100 shadow-[0_18px_40px_rgba(0,0,0,0.28)]",
className,
)}
{...props}
>
<div className="border-b border-neutral-800 px-5 py-4">
<div className="flex items-center gap-3">
<div className="flex size-10 items-center justify-center rounded-2xl bg-amber-500/15 text-amber-300">
<Coffee size={18} aria-hidden />
</div>
<div>
<h3 className="text-base font-semibold tracking-tight">
{cafeName}
</h3>
<p className="text-xs text-neutral-400">{tagline}</p>
</div>
</div>
</div>
 
<ul className="space-y-0 px-5 py-4">
{items.map((item, index) => (
<li
key={item.name}
className={cn(
"py-3",
index < items.length - 1
? "border-b border-neutral-800/80"
: undefined,
)}
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-sm font-medium text-neutral-100">
{item.name}
</p>
{item.note ? (
<p className="mt-0.5 text-[11px] text-neutral-500">
{item.note}
</p>
) : null}
</div>
<p className="shrink-0 text-sm font-semibold text-amber-300">
{item.price}
</p>
</div>
</li>
))}
</ul>
</div>
);
},
);
 
CafeMenuBoardCard.displayName = "CafeMenuBoardCard";
PreviousNext

On this

page

Jump to a section on this page.

  • lib/cn.ts
  • components/text/cafe-menu-board-card.tsx
Platinum slotAvailable

Feature your product here.

Sticky card next to every component — highest-intent placement.

Claim this card