A two-column hero for a restaurant, cafe or bar. The left side has the name, a serif headline, a short description, a Book a table button, a menu link and the address and phone number. The right side is a dark green panel with an arched top that lists opening hours for all seven days. A small script reads the visitor's clock and highlights today's row with a Today label, so people see at a glance whether you are open. The palette is cream, deep green and a warm amber. On phones the text comes first and the hours panel sits underneath at full width.
import { useEffect, useState } from "react";
// Monday first. Set `hours` to "Closed" for a day off.
const hours = [
{ day: "Monday", hours: "Closed" },
{ day: "Tuesday", hours: "5pm to 10pm" },
{ day: "Wednesday", hours: "5pm to 10pm" },
{ day: "Thursday", hours: "12pm to 10pm" },
{ day: "Friday", hours: "12pm to 11pm" },
{ day: "Saturday", hours: "11am to 11pm" },
{ day: "Sunday", hours: "11am to 8pm" },
];
export default function RestaurantSplitHeroWithOpeningHours() {
const [today, setToday] = useState(-1);
useEffect(() => {
setToday((new Date().getDay() + 6) % 7);
}, []);
const ring = "focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-900 focus-visible:ring-offset-2 focus-visible:ring-offset-amber-50";
return (
<section className="bg-amber-50 px-6 py-16 text-emerald-950 sm:py-20">
<div className="mx-auto grid max-w-6xl items-center gap-14 lg:grid-cols-2 lg:gap-20">
<div>
<p className="text-xs font-semibold uppercase tracking-widest text-emerald-800">Fornello ยท Wood-fired kitchen</p>
<h1 className="mt-6 font-serif text-5xl leading-tight tracking-tight sm:text-6xl">
Slow dough, hot oven, <em className="text-emerald-800">long lunches.</em>
</h1>
<p className="mt-6 max-w-md text-lg leading-relaxed text-stone-700">
Sourdough pizza proved for 48 hours, small plates from the embers and a short list of wines we actually drink. Walk-ins welcome at the bar.
</p>
<div className="mt-9 flex flex-col gap-4 sm:flex-row sm:items-center sm:gap-7">
<a href="#" className={`inline-flex items-center justify-center gap-2.5 rounded-full bg-emerald-900 px-8 py-4 text-base font-semibold text-amber-50 transition hover:bg-emerald-800 ${ring}`}>
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" className="h-5 w-5"><path fillRule="evenodd" d="M6 2a.75.75 0 0 1 .75.75V4h6.5V2.75a.75.75 0 0 1 1.5 0V4h.75A2.5 2.5 0 0 1 18 6.5v9a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 2 15.5v-9A2.5 2.5 0 0 1 4.5 4h.75V2.75A.75.75 0 0 1 6 2ZM3.5 9v6.5a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1V9h-13Z" clipRule="evenodd" /></svg>
Book a table
</a>
<a href="#" className={`inline-flex min-h-[44px] items-center justify-center rounded-full px-2 text-base font-semibold text-emerald-950 underline decoration-emerald-800 decoration-2 underline-offset-8 hover:text-emerald-800 ${ring}`}>
See this week's menu
</a>
</div>
<dl className="mt-12 grid max-w-md grid-cols-2 gap-6 border-t border-emerald-900/20 pt-7 text-sm">
<div>
<dt className="font-semibold uppercase tracking-widest text-emerald-800">Find us</dt>
<dd className="mt-2 leading-relaxed text-stone-700">14 Marlow Street<br />Eastbank, EB4 2QT</dd>
</div>
<div>
<dt className="font-semibold uppercase tracking-widest text-emerald-800">Call</dt>
<dd className="mt-2 leading-relaxed text-stone-700">0117 496 0123<br />Groups of 8 or more</dd>
</div>
</dl>
</div>
<div className="mx-auto w-full max-w-md rounded-b-3xl rounded-t-full bg-emerald-950 px-7 pb-9 pt-16 text-amber-50 sm:px-12 sm:pb-12 sm:pt-24">
<svg viewBox="0 0 120 64" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true" className="mx-auto h-14 w-28 text-amber-300">
<path d="M6 62a54 54 0 0 1 108 0" /><path d="M24 62a36 36 0 0 1 72 0" /><path d="M42 62a18 18 0 0 1 36 0" /><path d="M2 62h116" />
</svg>
<h2 className="mt-6 text-center font-serif text-3xl">Opening hours</h2>
<table className="mt-7 w-full text-left text-base">
<caption className="sr-only">Fornello opening hours by day</caption>
<thead className="sr-only">
<tr><th scope="col">Day</th><th scope="col">Hours</th></tr>
</thead>
<tbody>
{hours.map((h, i) => {
const isToday = i === today;
return (
<tr key={h.day} className={`border-t border-amber-50/15 ${isToday ? "text-amber-300" : h.hours === "Closed" ? "text-emerald-200/80" : "text-amber-50"}`}>
<th scope="row" className={`py-3 pr-3 ${isToday ? "font-semibold" : "font-normal"}`}>
{h.day}
{isToday && <span className="ml-2.5 rounded-full bg-amber-300 px-2 py-0.5 text-xs font-semibold text-emerald-950">Today</span>}
</th>
<td className={`py-3 text-right tabular-nums ${isToday ? "font-semibold" : ""}`}>{h.hours}</td>
</tr>
);
})}
</tbody>
</table>
<p className="mt-6 border-t border-amber-50/15 pt-5 text-center text-sm leading-relaxed text-emerald-100">
Kitchen takes last orders 45 minutes before closing.
</p>
</div>
</div>
</section>
);
}
Install with one command: npx shadcn@latest add https://we.inc/r/restaurant-split-hero-with-opening-hours.json
After the component mounts, it reads the day of the week from the visitor's device with `new Date().getDay()`, converts it so Monday is first, and stores it in state. The matching row gets the highlight classes. It runs in an effect so the server and browser output match.
Not as written, because the hours are stored as display text. To add it, store opening and closing times as numbers alongside the text, compare them with the current time in the same effect and show an Open now or Closed label above the table.
Place an `<img>` with `object-cover` as the first child of the green panel and give the panel `overflow-hidden`, or put the photo in the left column under the buttons. Keep the text on a solid colour so it stays readable.
Write both in the `hours` text, for example 12pm to 3pm, 6pm to 10pm. The right column wraps onto two lines when it needs to.
Yes. People look in both places. Keep one source of truth, such as this array, and reuse it so the times never disagree.
Related: Split Hero with Email Capture, Local Service Hero with Quote Request Form, App Landing Hero with Phone Mockup, Button Set: Primary, Secondary, Ghost, Icon and Loading.
More hero sections or all free UI components. Start for free to have a full site built around it.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.