React semantic UI tutorial for beginners

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 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

1npx creat-react-app react-semantic-recipe

Let's install semantic ui in our application

1npm install semantic-ui-react semantic-ui-css

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

1import "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

reactjs semantic ui wireframe

react semantic ui

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

react semantic ui demo

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

1import React, { useState, useEffect, Fragment } from "react"
2import "./App.css"
3import {
4 Container,
5 Input,
6 Button,
7 Dropdown,
8 Loader,
9 Dimmer,
10 Card,
11} from "semantic-ui-react"
12
13import { useQuery } from "react-query"
14
15function App() {
16 const [currentCategory, setCurrentCategory] = useState(0)
17 const [selectedMealId, setSelectedMealId] = useState(null)
18
19 const { isLoading, error, data: categories } = useQuery(
20 "categories",
21 async () => {
22 let result = await fetch(
23 "https://www.themealdb.com/api/json/v1/1/categories.php"
24 ).then(res => res.json())
25 result = result.categories.map(item => {
26 return {
27 key: item.idCategory,
28 text: item.strCategory,
29 value: item.idCategory,
30 image: item.strCategoryThumb,
31 }
32 })
33 return result
34 }
35 )
36
37 const { data: meals } = useQuery(
38 ["meals", currentCategory, categories],
39 async (key, currentCategory, data) => {
40 let result = await fetch(
41 `https://www.themealdb.com/api/json/v1/1/filter.php?c=${data[currentCategory].text}`
42 ).then(res => res.json())
43
44 return result.meals
45 },
46 {
47 enabled: categories,
48 }
49 )
50
51 if (isLoading)
52 return (
53 <Dimmer active inverted>
54 <Loader inverted content="Loading" />
55 </Dimmer>
56 )
57 return (
58 <Container className="container" textAlign="center">
59 // Container Logic comes Here
60 </Container>
61 )
62}
63
64export 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 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.

1if (isLoading)
2 return (
3 <Dimmer active inverted>
4 <Loader inverted content="Loading" />
5 </Dimmer>
6 )

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.

1<div className="row">
2 <Input
3 className="search-input"
4 size="large"
5 value={searchTerm}
6 onChange={onSearchChange}
7 placeholder="Search Meal"
8 />
9 <Button onClick={onSearch} secondary>
10 Search
11 </Button>
12 <Dropdown
13 className="drop-down"
14 placeholder="Filter Category"
15 fluid
16 search
17 selection
18 value={categories[currentCategory].value}
19 onChange={(e, { value }) => {
20 setCurrentCategory(value[0] - 1)
21 }}
22 options={categories}
23 />
24</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.

1import React from "react"
2import { Card, Image, Icon, Grid } from "semantic-ui-react"
3const MealCard = ({ imageUrl, title, onClick }) => {
4 return (
5 <Card onClick={onClick}>
6 <Image src={imageUrl} wrapped ui={false} />
7 <Card.Content>
8 <Card.Header>{title}</Card.Header>
9 </Card.Content>
10 </Card>
11 )
12}
13
14export 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.

1{
2 meals &&
3 meals.map(meal => {
4 return (
5 <MealCard
6 title={meal.strMeal}
7 onClick={() => {
8 console.log("meal.idMeal", meal.idMeal)
9 setSelectedMealId(meal.idMeal)
10 }}
11 imageUrl={meal.strMealThumb}
12 />
13 )
14 })
15}

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.

1import React from "react"
2import { useQuery } from "react-query"
3import {
4 Container,
5 Input,
6 Button,
7 Dropdown,
8 Loader,
9 Dimmer,
10 Header,
11 Grid,
12} from "semantic-ui-react"
13const MealDetails = ({ mealId, onBackButtonClick }) => {
14 const { isLoading, error, data: meals } = useQuery(
15 ["categories", mealId],
16 async (key, mealId) => {
17 console.log("mealId", mealId)
18 let result = await fetch(
19 `https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealId}`
20 ).then(res => res.json())
21 console.log("result", result)
22 return result.meals
23 }
24 )
25
26 if (isLoading)
27 return (
28 <Dimmer active inverted>
29 <Loader inverted content="Loading" />
30 </Dimmer>
31 )
32
33 if (meals) {
34 console.log("meals", meals)
35 }
36 return (
37 <Container>
38 <Button secondary onClick={onBackButtonClick}>
39 Back
40 </Button>
41 <h4>{meals[0].strMeal}</h4>
42
43 <Grid divided="vertically">
44 <Grid.Row columns={2}>
45 <Grid.Column>
46 <Header as="h3">Category:</Header>
47 </Grid.Column>
48 <Grid.Column>
49 <p>{meals[0].strCategory}</p>
50 </Grid.Column>
51 </Grid.Row>
52 <Grid.Row columns={2}>
53 <Grid.Column>
54 <Header as="h3">Instruction:</Header>
55 </Grid.Column>
56 <Grid.Column>
57 <p>{meals[0].strInstructions}</p>
58 </Grid.Column>
59 </Grid.Row>
60 <Grid.Row columns={2}>
61 <Grid.Column>
62 <Header as="h3">Source:</Header>
63 </Grid.Column>
64 <Grid.Column>
65 <a href={meals[0].strSource}>Source</a>
66 </Grid.Column>
67 </Grid.Row>
68
69 <Grid.Row columns={2}>
70 <Grid.Column>
71 <Header as="h3">Video:</Header>
72 </Grid.Column>
73 <Grid.Column>
74 <a href={meals[0].strYoutube}>Video</a>
75 </Grid.Column>
76 </Grid.Row>
77 </Grid>
78 </Container>
79 )
80}
81
82export 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

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,

1<Grid.Row columns={2}>
2 <Grid.Column>
3 <Header as="h3">Category:</Header>
4 </Grid.Column>
5 <Grid.Column>
6 <p>{meals[0].strCategory}</p>
7 </Grid.Column>
8</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,

1import React, { useState, useEffect, Fragment } from "react"
2import "./App.css"
3import {
4 Container,
5 Input,
6 Button,
7 Dropdown,
8 Loader,
9 Dimmer,
10 Card,
11} from "semantic-ui-react"
12
13import { useQuery } from "react-query"
14
15import MealCard from "./components/MealCard"
16import MealDetails from "./components/MealDetails"
17
18function App() {
19 const [currentCategory, setCurrentCategory] = useState(0)
20 const [selectedMealId, setSelectedMealId] = useState(null)
21 const [searchTerm, setSearchTerm] = useState("")
22 const [isSearch, setSearch] = useState(false)
23
24 const { isLoading, error, data: categories } = useQuery(
25 "categories",
26 async () => {
27 let result = await fetch(
28 "https://www.themealdb.com/api/json/v1/1/categories.php"
29 ).then(res => res.json())
30 result = result.categories.map(item => {
31 return {
32 key: item.idCategory,
33 text: item.strCategory,
34 value: item.idCategory,
35 image: item.strCategoryThumb,
36 }
37 })
38 return result
39 }
40 )
41
42 const { data: meals } = useQuery(
43 ["meals", currentCategory, categories],
44 async (key, currentCategory, data) => {
45 let result = await fetch(
46 `https://www.themealdb.com/api/json/v1/1/filter.php?c=${data[currentCategory].text}`
47 ).then(res => res.json())
48
49 return result.meals
50 },
51 {
52 enabled: categories,
53 }
54 )
55
56 const { data: searchResults } = useQuery(
57 ["searchMeals", isSearch, searchTerm],
58 async (key, isSearch, searchTerm) => {
59 if (isSearch) {
60 let result = await fetch(
61 `https://www.themealdb.com/api/json/v1/1/search.php?s=${searchTerm}`
62 ).then(res => res.json())
63 console.log("result", result)
64 return result.meals
65 } else {
66 return []
67 }
68 }
69 )
70
71 const onSearch = () => {
72 setSearch(true)
73 }
74
75 const onSearchChange = e => {
76 setSearchTerm(e.target.value)
77 }
78
79 if (isLoading)
80 return (
81 <Dimmer active inverted>
82 <Loader inverted content="Loading" />
83 </Dimmer>
84 )
85 return (
86 <Container className="container" textAlign="center">
87 {selectedMealId ? (
88 <MealDetails
89 mealId={selectedMealId}
90 onBackButtonClick={() => setSelectedMealId(null)}
91 />
92 ) : (
93 <Fragment>
94 <div className="row">
95 <Input
96 className="search-input"
97 size="large"
98 value={searchTerm}
99 onChange={onSearchChange}
100 placeholder="Search Meal"
101 />
102 <Button onClick={onSearch} secondary>
103 Search
104 </Button>
105 <Dropdown
106 className="drop-down"
107 placeholder="Filter Category"
108 fluid
109 search
110 selection
111 value={categories[currentCategory].value}
112 onChange={(e, { value }) => {
113 setCurrentCategory(value[0] - 1)
114 }}
115 options={categories}
116 />
117 </div>
118
119 <Container className="container" textAlign="center">
120 <Card.Group itemsPerRow={4}>
121 {searchTerm && isSearch ? (
122 searchResults &&
123 searchResults.map(meal => {
124 return (
125 <MealCard
126 title={meal.strMeal}
127 onClick={() => {
128 console.log("meal.idMeal", meal.idMeal)
129 setSelectedMealId(meal.idMeal)
130 }}
131 imageUrl={meal.strMealThumb}
132 />
133 )
134 })
135 ) : (
136 <Fragment>
137 {meals &&
138 meals.map(meal => {
139 return (
140 <MealCard
141 title={meal.strMeal}
142 onClick={() => {
143 console.log("meal.idMeal", meal.idMeal)
144 setSelectedMealId(meal.idMeal)
145 }}
146 imageUrl={meal.strMealThumb}
147 />
148 )
149 })}
150 </Fragment>
151 )}
152 </Card.Group>
153 </Container>
154 </Fragment>
155 )}
156 </Container>
157 )
158}
159
160export default App

Checkout the Source code here

To Read More

How to build an Actionable data ta...

In this article, we will see how to build an Actionable data table using a react...

How to Integrate Google Sheet in No...

This article explains how to Integrated Google sheet with your Nodejs Applicatio...

Kubernetes for Nodejs developers

Do you keep hearing the word kubernetes in the tech community and you couldn't u...