Building the Emoji Search App in React from Scratch
Step-by-Step Implementation of Emoji Search App
This module walks through building the app from scratch. We will create the React project, set up file structure, and write the code.
Set up the environment
Install Node.js: Download and install Node.js (LTS version) from nodejs.org. Verify with node -v and npm -v.
Create React app: Open a terminal and run:
npx create-react-app emoji-search-app
This bootstraps a new React project in a folder named emoji-search-app. (CRA stands for Create React App and generates a preconfigured React setup.)
Start development server:
cd emoji-search-app
npm start
This opens the app in your browser at http://localhost:3000. The page will reload if you edit code.
Tip: You can also use yarn instead of npm (e.g. yarn create react-app emoji-search-app).
Now our environment is ready and the React app is running locally.
Create Application Structure (Directory Structure)
Once the app is created, the directory structure looks like this:
emoji-search-app/
├── node_modules/ # (automatically installed dependencies)
├── public/
│ ├── index.html # Main HTML page
│ └── favicon.ico # Icon
├── src/ # Source code
│ ├── App.js # Main app component
│ ├── App.css # Main CSS file
│ ├── index.js # Entry point (renders App)
│ └── components/ # (we will create this folder)
│ └── EmojiCard.js # Component to display each emoji
├── .gitignore
├── package.json
└── README.md
- public/index.html: The main HTML file. It has a <div id="root"></div> where our React app will be mounted.
- src/index.js: The JavaScript entry point. It renders the <App /> component into the root div.
- src/App.js: The root React component. We will write most of our logic here (state, fetch, render search box, etc.).
- src/App.css: Styles for the app. We will define styles for layout and emoji cards.
- src/components/EmojiCard.js: We create this new folder and file to hold a component that represents an individual emoji.
- package.json: Lists project dependencies (React, etc.) and scripts.
Steps needed (Implementation)
App.js
First, open src/App.js and replace its content with the following code:
import React, { useState, useEffect } from 'react';
import EmojiCard from './components/EmojiCard';
import './App.css';
function App() {
const [emojis, setEmojis] = useState([]); // All emojis from API
const [searchTerm, setSearchTerm] = useState(''); // User’s search input
const [copiedId, setCopiedId] = useState(null); // ID of copied emoji
// Fetch emoji data when the component mounts
useEffect(() => {
// Using EmojiHub API to get all emojis
fetch('https://emojihub.yurace.pro/api/all')
.then(response => response.json())
.then(data => {
setEmojis(data); // Save emoji data in state
})
.catch(err => console.error(err));
}, []);
// Handle input change
const handleSearchChange = (event) => {
setSearchTerm(event.target.value);
};
// Handle copying an emoji
const handleCopy = (id, char) => {
navigator.clipboard.writeText(char) // copy emoji to clipboard
.then(() => {
setCopiedId(id); // mark this emoji as copied
// Remove the "Copied!" message after 1 second
setTimeout(() => setCopiedId(null), 1000);
});
};
// Filter emojis based on searchTerm
const filtered = emojis.filter(emoji =>
emoji.name.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="App">
<h1>Emoji Search App</h1>
<input
type="text"
placeholder="Search emojis..."
value={searchTerm}
onChange={handleSearchChange}
/>
<div className="emoji-container">
{filtered.map((emoji, index) => (
<EmojiCard
key={index}
emoji={emoji}
copied={copiedId === emoji.name}
onCopy={() => handleCopy(emoji.name, String.fromCodePoint(parseInt(emoji.unicode[0].slice(2), 16)))}
/>
))}
</div>
</div>
);
}
export default App;Explanation:
- We import useState and useEffect from React.
- We declare three pieces of state: emojis (list from API), searchTerm (text input), and copiedId (which emoji was copied).
- In useEffect, we use fetch to get data from the EmojiHub API endpoint https://emojihub.yurace.pro/api/all. When the data arrives, we store it in emojis.
- handleSearchChange updates searchTerm as the user types.
- We filter emojis by name matching searchTerm. This filtered array is rendered in JSX.
- The input box and emoji cards are inside <div className="App">. The search box has a placeholder and its value is bound to searchTerm.
- We map over the filtered emojis and render an EmojiCard for each. We pass props: the emoji object, whether it’s currently copied, and a function onCopy.
- handleCopy uses navigator.clipboard.writeText to copy the emoji character. We then set copiedId to show a “Copied!” message in the EmojiCard, and clear it after 1 second.
EmojiCard.js
Create a new file at src/components/EmojiCard.js with this code:
import React from 'react';
function EmojiCard({ emoji, copied, onCopy }) {
return (
<div className="emoji-card" onClick={onCopy}>
{/* Render the emoji character from its HTML code */}
<div className="emoji-char" dangerouslySetInnerHTML={{ __html: emoji.htmlCode[0] }} />
<div className="emoji-name">{emoji.name}</div>
{copied && <div className="copied-label">Copied!</div>}
</div>
);
}
export default EmojiCard;Explanation:
- EmojiCard is a function component taking emoji, copied, and onCopy as props.
- It renders a container <div> with an onClick handler. When clicked, it calls onCopy.
- Inside, it shows the emoji symbol by using dangerouslySetInnerHTML on emoji.htmlCode[0]. (EmojiHub returns HTML entities like 😀, so we inject it as HTML to show the actual emoji.)
- It also displays the emoji’s name.
- If copied is true, we show a “Copied!” overlay. In CSS we will style .copied-label to appear on top of the card.
App.css
Open src/App.css and add styling:
.App {
text-align: center;
background-color: #1a1a1a;
color: white;
min-height: 100vh;
padding: 20px;
font-family: Arial, sans-serif;
}
input[type="text"] {
width: 80%;
padding: 10px;
font-size: 1rem;
border-radius: 5px;
margin-bottom: 20px;
}
.emoji-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 15px;
padding: 10px;
}
.emoji-card {
position: relative;
background-color: #333;
border-radius: 10px;
padding: 10px;
cursor: pointer;
transition: transform 0.1s;
}
.emoji-card:hover {
transform: scale(1.05);
}
.emoji-char {
font-size: 2.5rem;
}
.emoji-name {
margin-top: 5px;
font-size: 0.9rem;
}
.copied-label {
position: absolute;
top: 5px;
left: 0;
right: 0;
color: #000;
background-color: #0f0;
padding: 5px 0;
font-weight: bold;
border-radius: 10px 10px 0 0;
}Explanation:
- We give the app a dark background (#1a1a1a) and white text. The font is sans-serif for simplicity.
- The search input is styled to be wide and centered.
- .emoji-container uses CSS Grid to lay out emoji cards responsively.
- Each .emoji-card is a dark box (#333) with rounded corners. On hover, it slightly enlarges.
- .emoji-char sets the emoji’s font size big. .emoji-name is the label below it.
- .copied-label is absolutely positioned at the top of the card and has a bright background to show “Copied!” when active.
At this point, you can run npm start (or yarn start) and test the app. Typing in the search box filters emojis immediately, and clicking one copies it.











