Creating a Reactive Restaurant Grid with Filtering Using React and Tailwind CSS

Creating a Reactive Restaurant Grid with Filtering Using React and Tailwind CSS

·

4 min read

In the realm of web development, creating a delightful user experience is paramount. One way to achieve this is by presenting information in a visually appealing and easily navigable manner. In this article, we'll explore a React code snippet that accomplishes just that - showcasing top-rated menu items with dynamic filtering.

The Code Structure

Let's break down the provided React code:

App.js

import React from "react";
import Food from "./components/Food";

function App() {
  return (
    <div>
      <Food />
    </div>
  );
}

export default App;

This is the entry point where the Food component is rendered. The Food component is where the main functionality resides.

Food.js

import React, { useState } from 'react';

const data = [
  {
    id: 1,
    name: 'Double Cheeseburger',
    category: 'burger',
    image:
      'https://images.unsplash.com/photo-1607013251379-e6eecfffe234?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8YnVyZ2Vyc3xlbnwwfHwwfHw%3D&auto=format&fit=crop&w=1400&q=60',
    price: '$$$$',
  },
  {
    id: 2,
    name: 'Bacon Cheeseburger',
    category: 'burger',
    image:
      'https://images.unsplash.com/photo-1553979459-d2229ba7433b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTh8fGJ1cmdlcnN8ZW58MHx8MHx8&auto=format&fit=crop&w=1400&q=60',
    price: '$',
  },
  {
    id: 3,
    name: 'Mushroom Burger',
    category: 'burger',
    image:
      'https://images.unsplash.com/photo-1608767221051-2b9d18f35a2f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTV8fGJ1cmdlcnN8ZW58MHx8MHx8&auto=format&fit=crop&w=1400&q=60',
    price: '$$',
  },
  {
    id: 4,
    name: 'Loaded Burger',
    category: 'burger',
    image:
      'https://images.unsplash.com/photo-1568901346375-23c9450c58cd?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NHx8YnVyZ2Vyc3xlbnwwfHwwfHw%3D&auto=format&fit=crop&w=1400&q=60',
    price: '$$$',
  },
  {
    id: 5,
    name: 'Feta & Spinnach',
    category: 'pizza',
    image:
      'https://images.unsplash.com/photo-1593560708920-61dd98c46a4e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8OHx8cGl6emF8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$',
  },
  {
    id: 6,
    name: 'Supreme Pizza',
    category: 'pizza',
    image:
      'https://images.unsplash.com/photo-1604382355076-af4b0eb60143?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8N3x8cGl6emF8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$$',
  },
  {
    id: 7,
    name: 'Meat Lovers',
    category: 'pizza',
    image:
      'https://images.unsplash.com/photo-1628840042765-356cda07504e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTh8fHBpenphfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
    price: '$$$$',
  },
  {
    id: 8,
    name: 'Cheese Pizza',
    category: 'pizza',
    image:
      'https://images.unsplash.com/photo-1548369937-47519962c11a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8OXx8Y2hlZXNlJTIwcGl6emF8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$',
  },
  {
    id: 9,
    name: 'Kale Salad',
    category: 'salad',
    image:
      'https://images.unsplash.com/photo-1515543237350-b3eea1ec8082?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8c2FsYWQlMjBjZWFzYXJ8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$',
  },
  {
    id: 10,
    name: 'Ceasar Salad',
    category: 'salad',
    image:
      'https://images.unsplash.com/photo-1546793665-c74683f339c1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NHx8c2FsYWQlMjBjZWFzYXJ8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$$',
  },
  {
    id: 11,
    name: 'Loaded Salad',
    category: 'salad',
    image:
      'https://images.unsplash.com/photo-1540420773420-3366772f4999?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8c2FsYWR8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$$$',
  },
  {
    id: 12,
    name: 'Fruit Salad',
    category: 'salad',
    image:
      'https://images.unsplash.com/photo-1564093497595-593b96d80180?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NHx8ZnJ1aXQlMjBzYWxhZHxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=800&q=60',
    price: '$',
  },
  {
    id: 13,
    name: 'Wings',
    category: 'chicken',
    image:
      'https://images.unsplash.com/photo-1567620832903-9fc6debc209f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8Y2hpY2tlbiUyMGZvb2R8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$',
  },
  {
    id: 14,
    name: 'Baked Chicken',
    category: 'chicken',
    image:
      'https://images.unsplash.com/photo-1594221708779-94832f4320d1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Nnx8Y2hpY2tlbiUyMGZvb2R8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60',
    price: '$$$$',
  },
  {
    id: 15,
    name: 'Chicken Tenders',
    category: 'chicken',
    image:
      'https://images.unsplash.com/photo-1562967914-608f82629710?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fGNoaWNrZW4lMjBmb29kfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
    price: '$',
  },
  {
    id: 16,
    name: 'Chicken Kabob',
    category: 'chicken',
    image:
      'https://images.unsplash.com/photo-1603360946369-dc9bb6258143?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTN8fGNoaWNrZW4lMjBmb29kfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
    price: '$$$',
  },
];

const Food = () => {
  const [foods, setFoods] = useState(data);

  //   Filter Type burgers/pizza/etc
  const filterType = (category) => {
    setFoods(
      data.filter((item) => {
        return item.category === category;
      })
    );
  };

  //   Filter by price
  const filterPrice = (price) => {
    setFoods(
      data.filter((item) => {
        return item.price === price;
      })
    );
  };

  return (
    <div className='max-w-[1640px] m-auto px-4 py-12'>
      <h1 className='text-orange-600 font-bold text-4xl text-center'>
        Top Rated Menu Items
      </h1>

      {/* Filter Row */}
      <div className='flex flex-col lg:flex-row justify-between'>
        {/* Fliter Type */}
        <div>
          <p className='font-bold text-gray-700'>Filter Type</p>
          <div className='flex justfiy-between flex-wrap'>
            <button
              onClick={() => setFoods(data)}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              All
            </button>
            <button
              onClick={() => filterType('burger')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              Burgers
            </button>
            <button
              onClick={() => filterType('pizza')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              Pizza
            </button>
            <button
              onClick={() => filterType('salad')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              Salads
            </button>
            <button
              onClick={() => filterType('chicken')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              Chicken
            </button>
          </div>
        </div>

        {/* Filter Price */}
        <div>
          <p className='font-bold text-gray-700'>Filter Price</p>
          <div className='flex justify-between max-w-[390px] w-full'>
            <button
              onClick={() => filterPrice('$')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              $
            </button>
            <button
              onClick={() => filterPrice('$$')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              $$
            </button>
            <button
              onClick={() => filterPrice('$$$')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              $$$
            </button>
            <button
              onClick={() => filterPrice('$$$$')}
              className='m-1 border-orange-600 text-orange-600 hover:bg-orange-600 hover:text-white'
            >
              $$$$
            </button>
          </div>
        </div>
      </div>

      {/* Display foods */}
      <div className='grid grid-cols-2 lg:grid-cols-4 gap-6 pt-4'>
        {foods.map((item, index) => (
          <div
            key={index}
            className='border shadow-lg rounded-lg hover:scale-105 duration-300'
          >
            <img
              src={item.image}
              alt={item.name}
              className='w-full h-[200px] object-cover rounded-t-lg'
            />
            <div className='flex justify-between px-2 py-4'>
              <p className='font-bold'>{item.name}</p>
              <p>
                <span className='bg-orange-500 text-white p-1 rounded-full'>
                  {item.price}
                </span>
              </p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Food;

This component manages the state of displayed foods and provides filtering functionality based on type and price. It also renders a visually appealing grid of food items with their details.

Understanding the Functionality

Filtering by Type

The filterType function filters the displayed foods based on the selected category (burger, pizza, etc.). Each button associated with a category triggers this filter when clicked.

<button onClick={() => filterType('burger')} className='...'>
  Burgers
</button>

Filtering by Price

Similarly, the filterPrice function filters foods based on the selected price range. Each button associated with a price range triggers this filter when clicked.

<button onClick={() => filterPrice('$')} className='...'>
  $
</button>

Displaying Food Items

The code efficiently maps through the filtered foods array and displays each item in a visually appealing card format.

{foods.map((item, index) => (
  <div key={index} className='...'>
    {/* ... (Food item details) ... */}
  </div>
))}

Conclusion

This React code provides a robust foundation for displaying and dynamically filtering top-rated menu items. By understanding and customizing this code, developers can create engaging and user-friendly interfaces for showcasing a variety of content. Whether you're building a restaurant menu or any other categorized content display, this React setup can be a valuable starting point. Happy coding!