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.
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.
To learn how to build a react application with semantic ui. we will build a recipe application using MealDB API
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"1213import { useQuery } from "react-query"1415function App() {16 const [currentCategory, setCurrentCategory] = useState(0)17 const [selectedMealId, setSelectedMealId] = useState(null)1819 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 result34 }35 )3637 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())4344 return result.meals45 },46 {47 enabled: categories,48 }49 )5051 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 Here60 </Container>61 )62}6364export 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 <Input3 className="search-input"4 size="large"5 value={searchTerm}6 onChange={onSearchChange}7 placeholder="Search Meal"8 />9 <Button onClick={onSearch} secondary>10 Search11 </Button>12 <Dropdown13 className="drop-down"14 placeholder="Filter Category"15 fluid16 search17 selection18 value={categories[currentCategory].value}19 onChange={(e, { value }) => {20 setCurrentCategory(value[0] - 1)21 }}22 options={categories}23 />24</div>
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 boxloading
- it adds a loader inside of the input boxdisabled
- 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.
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.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}1314export 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 <MealCard6 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.meals23 }24 )2526 if (isLoading)27 return (28 <Dimmer active inverted>29 <Loader inverted content="Loading" />30 </Dimmer>31 )3233 if (meals) {34 console.log("meals", meals)35 }36 return (37 <Container>38 <Button secondary onClick={onBackButtonClick}>39 Back40 </Button>41 <h4>{meals[0].strMeal}</h4>4243 <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>6869 <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}8182export 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.
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.
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"1213import { useQuery } from "react-query"1415import MealCard from "./components/MealCard"16import MealDetails from "./components/MealDetails"1718function App() {19 const [currentCategory, setCurrentCategory] = useState(0)20 const [selectedMealId, setSelectedMealId] = useState(null)21 const [searchTerm, setSearchTerm] = useState("")22 const [isSearch, setSearch] = useState(false)2324 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 result39 }40 )4142 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())4849 return result.meals50 },51 {52 enabled: categories,53 }54 )5556 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.meals65 } else {66 return []67 }68 }69 )7071 const onSearch = () => {72 setSearch(true)73 }7475 const onSearchChange = e => {76 setSearchTerm(e.target.value)77 }7879 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 <MealDetails89 mealId={selectedMealId}90 onBackButtonClick={() => setSelectedMealId(null)}91 />92 ) : (93 <Fragment>94 <div className="row">95 <Input96 className="search-input"97 size="large"98 value={searchTerm}99 onChange={onSearchChange}100 placeholder="Search Meal"101 />102 <Button onClick={onSearch} secondary>103 Search104 </Button>105 <Dropdown106 className="drop-down"107 placeholder="Filter Category"108 fluid109 search110 selection111 value={categories[currentCategory].value}112 onChange={(e, { value }) => {113 setCurrentCategory(value[0] - 1)114 }}115 options={categories}116 />117 </div>118119 <Container className="container" textAlign="center">120 <Card.Group itemsPerRow={4}>121 {searchTerm && isSearch ? (122 searchResults &&123 searchResults.map(meal => {124 return (125 <MealCard126 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 <MealCard141 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}159160export default App
Checkout the Source code here
No spam, ever. Unsubscribe anytime.