React semantic UI tutorial for beginners
Tags: showdev, react, webdev, beginners
Published: 2020-09-18 07:27:43


Semantic UI is a framework to develop responsive applications. In this tutorial, we are going to see how to build a react application with react semantic UI library.

### Install and Setup

we will be using [react semantic ui](https://react.semantic-ui.com/) library for our application which a wrapper of semantic ui to use in react applications. we will create our react application using `create-react-app`

```bash
npx creat-react-app react-semantic-recipe
```

Let's install semantic ui in our application

```bash
npm install semantic-ui-react semantic-ui-css
```

Once, you install the package. import the css of semantic ui in your `index.js`

```js
import "semantic-ui-css/semantic.min.css"
```

Now, you can use semantic ui in your react components.

### Building semantic ui react application

To learn how to build a react application with semantic ui. we will build a recipe application using [MealDB API](https://www.themealdb.com/)

### reactjs semantic ui wireframe

![react semantic ui](https://dev-to-uploads.s3.amazonaws.com/i/lmdks6ykcojtc3lza71d.png)

### Functionalities

- User can search a Meal from the selected category
- User can change the meal category and it will show the meal based on the category
- User can click and read more information about a particular meal recipe.

## [Demo](https://ganeshmani.github.io/react-semanticui-recipes/)

![react semantic ui demo](https://dev-to-uploads.s3.amazonaws.com/i/p5ile1jqumqgrg17n578.gif)

Now, let's see how to build an application like this in this tutorial using reactjs semantic ui.

Firstly, let's split the wireframe into react components and implement them in our application.

On the left side screen, we have search and filter functionality. then, we have Meal cards which displays thumbnail and meal details.

the components would be Card,Input and Dropdown components.

Add the following code in `App.js`

```jsx
import React, { useState, useEffect, Fragment } from "react"
import "./App.css"
import {
  Container,
  Input,
  Button,
  Dropdown,
  Loader,
  Dimmer,
  Card,
} from "semantic-ui-react"

import { useQuery } from "react-query"

function App() {
  const [currentCategory, setCurrentCategory] = useState(0)
  const [selectedMealId, setSelectedMealId] = useState(null)

  const { isLoading, error, data: categories } = useQuery(
    "categories",
    async () => {
      let result = await fetch(
        "https://www.themealdb.com/api/json/v1/1/categories.php"
      ).then(res => res.json())
      result = result.categories.map(item => {
        return {
          key: item.idCategory,
          text: item.strCategory,
          value: item.idCategory,
          image: item.strCategoryThumb,
        }
      })
      return result
    }
  )

  const { data: meals } = useQuery(
    ["meals", currentCategory, categories],
    async (key, currentCategory, data) => {
      let result = await fetch(
        `https://www.themealdb.com/api/json/v1/1/filter.php?c=${data[currentCategory].text}`
      ).then(res => res.json())

      return result.meals
    },
    {
      enabled: categories,
    }
  )

  if (isLoading)
    return (
      <Dimmer active inverted>
        <Loader inverted content="Loading" />
      </Dimmer>
    )
  return (
    <Container className="container" textAlign="center">
      // Container Logic comes Here
    </Container>
  )
}

export default App
```

Here, we have the semantic ui `Container` which sets the responsive width for the component.

secondly, we fetch the meals and categories data from the mealdb API. we are using [react-query](https://react-query.tanstack.com/) to fetch the data from API.

When fetching the data, we need to show loader inside our component. To do that, we will be using `Loader` from semantic ui.

```jsx
if (isLoading)
  return (
    <Dimmer active inverted>
      <Loader inverted content="Loading" />
    </Dimmer>
  )
```

Then, we use the meal data to render it in the Card Components. categories data to render it inside DropDown.

Let's implement Search bar and Categories filter first.

```jsx
<div className="row">
  <Input
    className="search-input"
    size="large"
    value={searchTerm}
    onChange={onSearchChange}
    placeholder="Search Meal"
  />
  <Button onClick={onSearch} secondary>
    Search
  </Button>
  <Dropdown
    className="drop-down"
    placeholder="Filter Category"
    fluid
    search
    selection
    value={categories[currentCategory].value}
    onChange={(e, { value }) => {
      setCurrentCategory(value[0] - 1)
    }}
    options={categories}
  />
</div>
```

### react semantic ui input

Here, we use `Input` from semantic UI as a search input. we can add different props to change the behaviour of input.

- `focus` - it adds the focus border around the input box
- `loading` - it adds a loader inside of the input box
- `disabled` - it disables the option to edit our input.
- `error` - it shows the validation error inside of it.
- `icon` - it adds icon inside the input box.

There are all the major props inside the semantic UI Input Components.

### react semantic ui button

After that, we add button for search functionality. Let's see some of the important props in semantic ui to change the default button behaviour.

- `primary` - changes the color of button to primary color.
- `secondary` - it changes the color of button to secondary color.
- `active` - it shows the button active state.
- `disabled` - it shows the button disabled state.
- `loading` - you can add loader inside the button which is a nice way to show the progress or API call fetch.

### react semantic ui dropdown

Sematic UI adds lots of variation in the dropdown. few important one's are Searchable Dropdown, Multi Selection, clearable selection.

- `search` - it makes the default dropdown searchable.
- `multiple` - it makes the default dropdown a multiple selection one.
- `clearable` - it makes it clearable dropdown.

Now, we have implemented top part of our application. it's time to implment the Card component and show the Meal inside of it.

create `MealCard/index.js` and add the following code to create semantic UI Card.

```jsx
import React from "react"
import { Card, Image, Icon, Grid } from "semantic-ui-react"
const MealCard = ({ imageUrl, title, onClick }) => {
  return (
    <Card onClick={onClick}>
      <Image src={imageUrl} wrapped ui={false} />
      <Card.Content>
        <Card.Header>{title}</Card.Header>
      </Card.Content>
    </Card>
  )
}

export default MealCard
```

Here, we add the Card from semantic UI which takes Content,Header and body.Also, we use only Content and Header from the semantic UI Card.

Once you implement this component. we can use it inside `App.js`.

```jsx
{
  meals &&
    meals.map(meal => {
      return (
        <MealCard
          title={meal.strMeal}
          onClick={() => {
            console.log("meal.idMeal", meal.idMeal)
            setSelectedMealId(meal.idMeal)
          }}
          imageUrl={meal.strMealThumb}
        />
      )
    })
}
```

we loop through `meals` from the API fetch data and render our `MealCard` inside it.

Now, that we have rendered our Meal inside the card. When user clicks the card, we need to show all the details about the Meal.

Let's implement the functionalities inside a component `MealDetails/index.js` inside out components directory.

```jsx
import React from "react"
import { useQuery } from "react-query"
import {
  Container,
  Input,
  Button,
  Dropdown,
  Loader,
  Dimmer,
  Header,
  Grid,
} from "semantic-ui-react"
const MealDetails = ({ mealId, onBackButtonClick }) => {
  const { isLoading, error, data: meals } = useQuery(
    ["categories", mealId],
    async (key, mealId) => {
      console.log("mealId", mealId)
      let result = await fetch(
        `https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealId}`
      ).then(res => res.json())
      console.log("result", result)
      return result.meals
    }
  )

  if (isLoading)
    return (
      <Dimmer active inverted>
        <Loader inverted content="Loading" />
      </Dimmer>
    )

  if (meals) {
    console.log("meals", meals)
  }
  return (
    <Container>
      <Button secondary onClick={onBackButtonClick}>
        Back
      </Button>
      <h4>{meals[0].strMeal}</h4>

      <Grid divided="vertically">
        <Grid.Row columns={2}>
          <Grid.Column>
            <Header as="h3">Category:</Header>
          </Grid.Column>
          <Grid.Column>
            <p>{meals[0].strCategory}</p>
          </Grid.Column>
        </Grid.Row>
        <Grid.Row columns={2}>
          <Grid.Column>
            <Header as="h3">Instruction:</Header>
          </Grid.Column>
          <Grid.Column>
            <p>{meals[0].strInstructions}</p>
          </Grid.Column>
        </Grid.Row>
        <Grid.Row columns={2}>
          <Grid.Column>
            <Header as="h3">Source:</Header>
          </Grid.Column>
          <Grid.Column>
            <a href={meals[0].strSource}>Source</a>
          </Grid.Column>
        </Grid.Row>

        <Grid.Row columns={2}>
          <Grid.Column>
            <Header as="h3">Video:</Header>
          </Grid.Column>
          <Grid.Column>
            <a href={meals[0].strYoutube}>Video</a>
          </Grid.Column>
        </Grid.Row>
      </Grid>
    </Container>
  )
}

export default MealDetails
```

Here, we take two props which are `mealId` and back button click function as props.

based on the mealId, we need to show the details. we use Semantic UI Grid to show the data. if you see the wireframe, we have property name in the left side and value in the right side.

For example, Instruction key in the left side and value for that will be in the right side.

you can use Grid to achieve any kind of alignment in the web application.

![react semantic ui grid](https://dev-to-uploads.s3.amazonaws.com/i/wixo1x6204ypdytwwd3s.png)

### react semantic ui grid

Concept of react semantic ui grid is simple. There are rows and columns. you just need to specify the number of columns inside the Row and add the component inside the `Grid.Column`

For example,

```jsx
<Grid.Row columns={2}>
  <Grid.Column>
    <Header as="h3">Category:</Header>
  </Grid.Column>
  <Grid.Column>
    <p>{meals[0].strCategory}</p>
  </Grid.Column>
</Grid.Row>
```

Here we specify two columns and add our component Header inside the `Grid.Column`.

react semantic ui header is straight forward. so, i leave it upto you to implement it.

Now, we need to add the component inside our `App.js`.There are two ways to implement this functionality.

- We can have a router, which routes to the meal details page based on the selected meal id. For example, it redirects to /meal/12 and we can get the id from there.
- we can store the selected meal id in the state and use it to conditional render the Meal details component inside `App.js`.

In this application , we will be using second approach because, our application is small and simple. if you're building a larger application. first approach is more appropriate.

our final `App.js` would look like,

```jsx
import React, { useState, useEffect, Fragment } from "react"
import "./App.css"
import {
  Container,
  Input,
  Button,
  Dropdown,
  Loader,
  Dimmer,
  Card,
} from "semantic-ui-react"

import { useQuery } from "react-query"

import MealCard from "./components/MealCard"
import MealDetails from "./components/MealDetails"

function App() {
  const [currentCategory, setCurrentCategory] = useState(0)
  const [selectedMealId, setSelectedMealId] = useState(null)
  const [searchTerm, setSearchTerm] = useState("")
  const [isSearch, setSearch] = useState(false)

  const { isLoading, error, data: categories } = useQuery(
    "categories",
    async () => {
      let result = await fetch(
        "https://www.themealdb.com/api/json/v1/1/categories.php"
      ).then(res => res.json())
      result = result.categories.map(item => {
        return {
          key: item.idCategory,
          text: item.strCategory,
          value: item.idCategory,
          image: item.strCategoryThumb,
        }
      })
      return result
    }
  )

  const { data: meals } = useQuery(
    ["meals", currentCategory, categories],
    async (key, currentCategory, data) => {
      let result = await fetch(
        `https://www.themealdb.com/api/json/v1/1/filter.php?c=${data[currentCategory].text}`
      ).then(res => res.json())

      return result.meals
    },
    {
      enabled: categories,
    }
  )

  const { data: searchResults } = useQuery(
    ["searchMeals", isSearch, searchTerm],
    async (key, isSearch, searchTerm) => {
      if (isSearch) {
        let result = await fetch(
          `https://www.themealdb.com/api/json/v1/1/search.php?s=${searchTerm}`
        ).then(res => res.json())
        console.log("result", result)
        return result.meals
      } else {
        return []
      }
    }
  )

  const onSearch = () => {
    setSearch(true)
  }

  const onSearchChange = e => {
    setSearchTerm(e.target.value)
  }

  if (isLoading)
    return (
      <Dimmer active inverted>
        <Loader inverted content="Loading" />
      </Dimmer>
    )
  return (
    <Container className="container" textAlign="center">
      {selectedMealId ? (
        <MealDetails
          mealId={selectedMealId}
          onBackButtonClick={() => setSelectedMealId(null)}
        />
      ) : (
        <Fragment>
          <div className="row">
            <Input
              className="search-input"
              size="large"
              value={searchTerm}
              onChange={onSearchChange}
              placeholder="Search Meal"
            />
            <Button onClick={onSearch} secondary>
              Search
            </Button>
            <Dropdown
              className="drop-down"
              placeholder="Filter Category"
              fluid
              search
              selection
              value={categories[currentCategory].value}
              onChange={(e, { value }) => {
                setCurrentCategory(value[0] - 1)
              }}
              options={categories}
            />
          </div>

          <Container className="container" textAlign="center">
            <Card.Group itemsPerRow={4}>
              {searchTerm && isSearch ? (
                searchResults &&
                searchResults.map(meal => {
                  return (
                    <MealCard
                      title={meal.strMeal}
                      onClick={() => {
                        console.log("meal.idMeal", meal.idMeal)
                        setSelectedMealId(meal.idMeal)
                      }}
                      imageUrl={meal.strMealThumb}
                    />
                  )
                })
              ) : (
                <Fragment>
                  {meals &&
                    meals.map(meal => {
                      return (
                        <MealCard
                          title={meal.strMeal}
                          onClick={() => {
                            console.log("meal.idMeal", meal.idMeal)
                            setSelectedMealId(meal.idMeal)
                          }}
                          imageUrl={meal.strMealThumb}
                        />
                      )
                    })}
                </Fragment>
              )}
            </Card.Group>
          </Container>
        </Fragment>
      )}
    </Container>
  )
}

export default App
```

Checkout the Source code [here](https://github.com/ganeshmani/react-semanticui-recipes)