shadcn.io is not affiliated with official shadcn/ui
Restaurant Menu Table Block for Solid
A seaside restaurant's dinner menu in three category groups with dietary codes, spice shown as drawn dots and a word, prices at the end, and a diet filter that dims dishes instead of hiding them.
Installation
Overview
Let diners find what they can eat without losing the menu, with this restaurant menu table for Solid with Ark UI. A compact header names the menu and, at its end, holds a Toggle Group of four diets, Vegetarian, Vegan, Gluten-free and Nut-free, any number of which can be pressed. A native table lists twelve dishes from Tidewater Kitchen under three category rows (Starters, Mains and Desserts) that span the table. A dish shows its description under its name, its dietary codes in outline Badges, its spice as zero to three drawn dots and a word, and its price at the end; a dish that is out shows "Sold out" as plain text in the price cell. Pressing a diet dims every dish that doesn't carry all the diets pressed with a solid tint and softer text, never a hidden row, and a polite line counts "7 of 12 dishes match"; each dimmed dish also says "does not match" to assistive technology. The rows never move, so the menu keeps its size with any combination. It's built from Toggle Group, Badge, Guides and a native table, with a CSS entrance only. For menus, product lists, catalogues and any table where a filter should show what is left out.
FAQ
How do I change the dishes and the diets?
Edit DISHES (each has a category, a description, the diets it carries, a price, a spice level from 0 to 3 and a soldOut flag) and CHOICES for the diets and their codes. matches is the rule: a dish matches when it carries every diet pressed, and with none pressed everything matches. Add a category by adding its name to CATEGORIES; each one gets its own row group.
Why dim dishes instead of hiding them?
Because the whole menu stays in view and in place: a diner sees what the kitchen offers and what to avoid, and the rows don't jump as diets are pressed. A dimmed dish gets a solid 5% tint and softer text that still passes contrast, and the words "does not match" are added for screen readers, so the state is never only visual. A sold-out dish isn't dimmed for being sold out: "Sold out" is plain text in the price cell.
What stays local, and how do I wire it to real data?
The menu and the diets pressed live in the page; nothing is saved or requested. In your own app, send dishes with their allergens and diets from your system, and keep matches as the single place the rule lives. Treat the filter as a convenience: the allergen information the restaurant is legally responsible for should come from its own source and be confirmed with the kitchen.
Is it accessible?
Yes. The diet control is a group of toggle buttons with a name, each reporting whether it is pressed, and a polite status line counts the matches after every press. The table has a caption, th scope="col" heads, category rows as colgroup headings and each dish as the row header. Dietary codes carry their full words for screen readers, spice has a word as well as dots, and the dots are decorative.
How does it look on a phone?
The table keeps its four columns: the dish with its description, narrow Dietary and Spice columns and the price. On a phone the spice word is spoken but not shown, leaving the dots, and the codes wrap onto two lines when a dish has several. The diet toggles wrap under the header.