Easy Flashcards
Easy level React coding assignments (23 cards)
Chips Input
Description
In this task, you are asked to create a Chips Input component that allows users to input a series of tags or keywords. The component will display these tags as “chips” (small labels), which users can add and remove dynamically.
Features:
1. Input Field: Users can type text into an input field.
2. Add Chips: When the user presses the “Enter” key, the typed text will be added as a new chip (tag). Empty or whitespace-only chips should not be added
3. Remove Chips: Users can delete a chip by clicking the
“X” button next to it.
4. Horizontal Display: The chips should be displayed in a horizontal list.
5. Persistence: The list of chips should be maintained even when the component re-renders.
Important Points:
1. The input field should be of type text.
2. Button should be labeled “X” to delete chips
3. If two chips have the same name, deleting one should NOT delete both.
4. Make sure to use onKeyDown event handler instead of onKeyPress because onKeyPress is deprecated.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
ChipsInput.js
import React, { useState } from "react"; import './styles.css' function ChipsInput() { return ( <div style={{display:"flex", flexDirection:"column",alignItems:"center", margin:"40px 0"}}> <h2>Chips Input</h2> <input type="text" placeholder="Type a chip and press tag" style={{ padding: "8px", width: "200px" }} /> </div> ); } export default ChipsInput;
App.js
import ChipsInput from './ChipsInput.js' export default function App() { return <ChipsInput/> }
https://namastedev.com/practice/chips-input
style.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; } .chips-container { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px; } .chip { background-color: #e0e0e0; border-radius: 16px; padding: 4px 12px; display: flex; align-items: center; font-size: 14px; } .chip button { margin-left: 8px; border: none; background: transparent; cursor: pointer; font-weight: bold; color: red; } .chips-input-field { margin-top: 8px; padding: 6px; font-size: 16px; width: 100%; max-width: 300px; } .chip { transition: background-color 0.2s ease; }
ChipsInput.js
import React, { useState } from "react"; import './styles.css' function ChipsInput() { const [chips, setChips] = useState([]); const [inputValue, setInputValue] = useState(''); const handleKeyDown = (e) => { if (e.key === 'Enter') { const trimmed = inputValue.trim(); if (trimmed !== '') { setChips([...chips, trimmed]); setInputValue(''); } } }; const handleDelete = (indexToDelete) => { setChips(chips.filter((_, index) => index !== indexToDelete)); }; return ( <div style={{display:"flex", flexDirection:"column",alignItems:"center", margin:"40px 0"}}> <h2>Chips Input</h2> <input type="text" placeholder="Type a chip and press tag" style={{ padding: "8px", width: "200px" }} onChange={(e) => setInputValue(e.target.value)} value={inputValue} onKeyDown={handleKeyDown} /> <div className="chips-container"> {chips.map((chip, index) => ( <span className="chip" key={index}> {chip} <button onClick={() => handleDelete(index)}>X</button> </span> ))} </div> </div> ); } export default ChipsInput;
App.js
import ChipsInput from './ChipsInput.js' export default function App() { return <ChipsInput/> }
Style Reasoning:
🔤 1. Base Typography and Text Rendering
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }
Why these styles?
* Ensures text looks crisp and readable on most platforms (especially macOS and iOS).
* text-rendering: optimizeLegibility; improves kerning and ligatures.
* -webkit-tap-highlight-color: transparent and -webkit-touch-callout: none remove blue highlight and callout menus on mobile taps — better UX for touch devices.
✨ This base styling is often used in production apps for consistent cross-device font rendering and interaction.
🧱 2. Basic Layout: Headings and Container
h1 { font-size: 1.5rem; }
Why this?
* Slightly smaller and more modern than default browser h1. Fits better in components-focused UIs.
.chips-container { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px; }
Why this?
* flex + wrap: Allows chips to flow to the next line when there’s not enough space.
* gap: Adds consistent spacing between chips — cleaner than using margin.
* padding: Adds internal spacing so chips don’t hug the edge of the container.
🏷️ 3. Chips Design
.chip { background-color: #e0e0e0; border-radius: 16px; padding: 4px 12px; display: flex; align-items: center; font-size: 14px; }
Why this?
* Light gray background for neutral appearance.
* border-radius: 16px: Rounded pill-style shape — visually familiar as “chip”.
* padding gives breathing room around text.
* display: flex + align-items: center: Ensures text and “X” button align vertically.
.chip button { margin-left: 8px; border: none; background: transparent; cursor: pointer; font-weight: bold; color: red; }
Why this?
* “X” button feels integrated into chip (no border/background).
* Red color: visually distinct for a delete action.
* cursor: pointer signals interactivity.
🎯 4. Input Field Styling
.chips-input-field { margin-top: 8px; padding: 6px; font-size: 16px; width: 100%; max-width: 300px; }
Why this?
* margin-top: Separates from chips for clarity.
* padding: Improves tap/click target.
* max-width: Keeps UI tidy and limits excessive horizontal growth.
* font-size: Matches body text size for readability.
✨ 5. Enhancement: Smooth Transitions
.chip { transition: background-color 0.2s ease; }
Why this?
* Smooth transitions make the UI feel more modern and responsive.
* Prepares the chip for future enhancements like hover effects or animation when removed.
✅ Summary
| Step | Goal | Style |
| —- | —————————————— | ———————————– |
| 1. | Consistent, legible fonts across platforms | font-smoothing
, text-rendering
|
| 2. | Clean layout for wrapping chips | flex-wrap
, gap
, padding
|
| 3. | Chip UI & delete behavior | border-radius
, button
, color
|
| 4. | Usable input field | max-width
, font-size
, padding
|
| 5. | Add polish | transition
|
Guess the Number
Description
Build a “Guess the Number” game where the user tries to guess a randomly generated number between 1 and 100. The game provides feedback after each guess and tracks the number of attempts.
Requirements
1. Generate a Random Number
* Random number between 1 and 100 (inclusive) is generated at the start of the game.
2. User Input
* User enters a guess between 1 and 100.
* The input field must have an id=”guess-input” for easy testing.
- Feedback After Each Guess
* Correct Guess: “Congratulations! You guessed the number in X attempts.”
* Guess is less than Random number: “Too low! Try again.”
* Guess is greater than Random number: “Too high! Try again.”
* Invalid Input: “Please enter a number between 1 and 100.” - Track Attempts
* Keep count of the number of guesses made. - Buttons and Their Functions
* A button labelled “Reset Game” starts a new game.
* A button labeled “Check Guess” checks the current guess and give feedback
Input/Output Example
Input: 50
Output: Too high! Try again.
Input: 30
Output: Too low! Try again.
Input: 40
Output: Congratulations! You guessed the number i
Input: 105
Output: Please enter a number between 1 and 100.
Input: apple
Output: Please enter a number between 1 and 100.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
GuessTheNumber.jsx
import React, { useState } from "react"; import './styles.css' function GuessTheNumber() { // Function to handle guess checking const handleGuess = () => { }; // Function to reset the game const resetGame = () => { }; return ( <div style={{display:"flex", flexDirection:"column", alignItems:"center", margin:"50px 0"}}> <h2>Guess the Number</h2> <input placeholder="Enter a number between 1 and 100" style={{width:"300px",padding:"5px"}} id="guess-input" /> </div> ); } export default GuessTheNumber;
App.js
import GuessTheNumber from './GuessTheNumber' export default function App() { return <GuessTheNumber/> }
https://namastedev.com/practice/guess-the-number
style.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; } .game-container { max-width: 400px; margin: 50px auto; text-align: center; background-color: #f9f9f9; padding: 24px; border-radius: 16px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1); } .guess-input { width: 80%; max-width: 300px; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 8px; margin-bottom: 16px; } .button-row { display: flex; justify-content: center; gap: 10px; margin-bottom: 16px; } .button-row button { padding: 8px 16px; font-size: 14px; border: none; border-radius: 8px; cursor: pointer; transition: background-color 0.3s ease; color: white; } .button-row button:first-child { background-color: #4caf50; } .button-row button:first-child:hover { background-color: #388e3c; } .button-row button:last-child { background-color: #f44336; } .button-row button:last-child:hover { background-color: #d32f2f; } .feedback { font-weight: bold; margin-bottom: 8px; } .attempts { color: #666; font-size: 14px; }
GuessTheNumber.jsx
import React, { useState } from "react"; import './styles.css' function GuessTheNumber() { const getRandomNumber = () => Math.floor(Math.random() * 100) + 1; const [randomNumber, setRandomNumber] = useState(getRandomNumber); const [guess, setGuess] = useState(''); const [feedback, setFeedback] = useState(''); const [attempts, setAttempts] = useState(0); const handleGuess = () => { const num = Number(guess.trim()); if (isNaN(num) || num < 1 || num > 100) { setFeedback("Please enter a number between 1 and 100."); return; } setAttempts(attempts + 1); if (num === randomNumber) { setFeedback(`🎉 Congratulations! You guessed the number in ${attempts + 1} attempts.`); } else if (num < randomNumber) { setFeedback("Too low! Try again."); } else { setFeedback("Too high! Try again."); } }; const resetGame = () => { setRandomNumber(getRandomNumber()); setGuess(''); setFeedback(''); setAttempts(0); }; return ( <div className="game-container"> <h2>Guess the Number</h2> <input id="guess-input" placeholder="Enter a number between 1 and 100" value={guess} onChange={(e) => setGuess(e.target.value)} className="guess-input" /> <div className="button-row"> <button onClick={handleGuess}>Check Guess</button> <button onClick={resetGame}>Reset Game</button> </div> <p className="feedback">{feedback}</p> <p className="attempts">Attempts: {attempts}</p> </div> ); } export default GuessTheNumber;
App.js
import GuessTheNumber from './GuessTheNumber' export default function App() { return <GuessTheNumber/> }
🔧 Step-by-Step Styling Evolution
1. 🎁 Add a wrapper class
Gives the game structure and central alignment.
.game-container { max-width: 400px; margin: 50px auto; text-align: center; background-color: #f9f9f9; padding: 24px; border-radius: 16px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1); }
Progress Bar
Description:
Create a Progress Bar Component in React that visually represents a single progress value. Users should be able to increment or decrement progress using buttons. Make sure to use inline css.
Requirements
1. Display one progress bar.
2. The bar should reflect a numeric progress (0-100%).
3. Include buttons labeled ‘+10%’ and ‘-10%’ to increase or decrease the bar’s value.
4. Prevent values from going below 0% or above 100%.
5. Change bar color based on value (e.g., red, orange, green).
6. Color is selected based on thresholds:
* Red if less than 40%
* Orange if between 40-79%
* Green if 80% or more
Constraints & Edge Casès
* Constraint 1: Progress must stay between 0 and 100.
* Constraint 2: The background color-changing div must have an id=”testBgColor” for testing the background color of progress bar.
* Edge Case 1: If decrementing would take a value below
0, clamp it to 0.
* Edge Case 2: If incrementing would take a value above
100, clamp it to 100.
ProgressBars.js
import React from "react"; function ProgressBar() { return ( <div> {/* Implement the ProgressBar component logic here */} </div> ); } export default ProgressBar;
App.js
import ProgressBars from "./ProgressBars"; export default function App() { return <ProgressBars />; }
https://namastedev.com/practice/progress-bar
ProgressBars.js
import React, { useState } from "react"; function ProgressBar() { const [progress, setProgress] = useState(0); // Clamp value between 0 and 100 const clamp = (value) => Math.max(0, Math.min(100, value)); // Increase by 10 const increment = () => { setProgress((prev) => clamp(prev + 10)); }; // Decrease by 10 const decrement = () => { setProgress((prev) => clamp(prev - 10)); }; // Determine color based on progress const getColor = () => { if (progress < 40) return "red"; if (progress < 80) return "orange"; return "green"; }; return ( <div style={{ textAlign: "center", marginTop: "50px" }}> <h2>Progress: {progress}%</h2> <div style={{ width: "80%", height: "30px", border: "1px solid #ccc", borderRadius: "8px", margin: "auto", overflow: "hidden", }} > <div id="testBgColor" style={{ height: "100%", width: `${progress}%`, backgroundColor: getColor(), transition: "width 0.3s ease", }} /> </div> <div style={{ marginTop: "20px" }}> <button onClick={decrement} style={{ padding: "10px 20px", marginRight: "10px", fontSize: "16px", cursor: "pointer", }} > -10% </button> <button onClick={increment} style={{ padding: "10px 20px", fontSize: "16px", cursor: "pointer", }} > \+10% </button> </div> </div> ); } export default ProgressBar;
App.js
import ProgressBars from "./ProgressBars"; export default function App() { return <ProgressBars />; }
Array to Zigzag String Converter
Description
Create a React component that allows users to input multiple comma-separated strings and outputs a zigzag merged string.
The component merges the strings such that strings at even indices are appended as is, while strings at odd indices are reversed before appending.
Requirements
* A user can enter multiple strings separated by commas. in an input field.
The input box should have a placeholder like “Enter strings like one,two,three”
* A button is provided to trigger the merging operation.
* Upon clicking the button:
The input string is split by commas into an array.
Each string at an even index (0, 2, 4, …) is kept as is.
Each string at an odd index (1, 3, 5, …) is reversed.
All strings are joined together without any separator.
The merged string is displayed prefixed with “Output:
* If the input is empty or only spaces, the output should be empty.
Edge Cases & Constraints
* Input strings may contain spaces around commas; these should be trimmed.
* Empty input should result in empty output.
* Strings can contain special characters and numbers.
* Large or long strings should be handled correctly.
* The output concatenates all processed strings in zigzag order without spaces.
Example Inputs & Outputs
// Example 1: Two words input
Input: “hello, world”
Output: “Output: hellodlrow”
// Example 2: Single word input
Input: “single”
Output: “Output: single”
// Example 3: Multiple words
Input: “one, two, three, four”
Output: “Output: oneowtthreeruof”
// Example 4: Input with special characters
Input: “zig, zag!, foo#, bar$”
Output: “Output: zig!gazfoo#$rab”
// Example 5: Empty input
Input: “”
Output: “Output: “
Testing Requirements
* Verify that the input box has the correct placeholder text: “Enter strings like one,two,three”:
* Test that entering comma-separated strings and clicking submit produces the expected zigzag merged output.
* Test that single word inputs are handled correctly and the output should also be a single word.
* Test that empty input results in an empty output string.
* Test that input with special characters and numbers merges correctly with odd-index strings reversed.
* Confirm the output text is always prefixed with “Output:
* Confirm that leading and trailing spaces in input strings are trimmed before processing.
Data Test IDs (required for testing)
* data-testid=”input-box”: The input field where the user types comma-separated strings.
* data-testid=”submit-button”: The button which triggers the zigzag merging process.
* data-testid=”output-result”: The paragraph or element that displays the output result.
App.js
import React from "react"; import "./styles.css"; import ZigzagString from "./ZigzagString"; export default function App() { return ( <div className="container"> <h1>Array to Zigzag String</h1> <ZigzagString /> </div> ); }
ZigzagString.js
import React from "react"; import "./styles.css"; import ZigzagString from "./ZigzagString"; export default function App() { return ( <div className="container"> <h1>Array to Zigzag String</h1> <ZigzagString /> </div> ); }
https://namastedev.com/practice/array-to-zigzag-string-converter
ZigzagString.js
import React, { useState } from "react"; function ZigzagString() { const [input, setInput] = useState(""); const [output, setOutput] = useState(""); const handleMerge = () => { const trimmed = input.trim(); if (!trimmed) { setOutput("Output: "); return; } const parts = trimmed .split(",") .map((p) => p.trim()) .filter((s) => s.length > 0); const result = parts .map((str, i) => (i % 2 === 0 ? str : str.split("").reverse().join(""))) .join(""); setOutput(`Output: ${result}`); }; return ( <div style={{ maxWidth: "500px", margin: "50px auto", padding: "24px", textAlign: "center", backgroundColor: "#fff", borderRadius: "12px", boxShadow: "0 6px 18px rgba(0,0,0,0.1)", fontFamily: "sans-serif", }} > <input type="text" placeholder="Enter strings like one,two,three" value={input} onChange={(e) => setInput(e.target.value)} data-testid="input-box" style={{ padding: "10px", width: "100%", maxWidth: "350px", fontSize: "16px", border: "1px solid #ccc", borderRadius: "8px", marginBottom: "16px", }} /> <br /> <button onClick={handleMerge} data-testid="submit-button" style={{ padding: "10px 20px", fontSize: "14px", backgroundColor: "#4caf50", color: "white", border: "none", borderRadius: "8px", cursor: "pointer", transition: "background-color 0.3s ease", }} onMouseOver={(e) => (e.target.style.backgroundColor = "#388e3c")} onMouseOut={(e) => (e.target.style.backgroundColor = "#4caf50")} > Merge Strings </button> <p data-testid="output-result" style={{ fontWeight: "bold", color: "#333", fontSize: "18px", marginTop: "20px", }} > {output} </p> </div> ); } export default ZigzagString;
App.js
import React from "react"; import ZigzagString from "./ZigzagString"; export default function App() { return ( <div style={{ padding: "20px" }}> <h1 style={{ textAlign: "center", fontFamily: "sans-serif" }}> Array to Zigzag String </h1> <ZigzagString /> </div> ); }
Tooltip
Description
Create a class-based React component named Tooltip that displays a list of icons. When a user hovers over an icon, a tooltip should appear showing the name of that icon.
This question tests your ability to handle mouse events (onMouseEnter, onMouseLeave), maintain component state, and use conditional rendering to show or hide Ul elements dynamically.
You must use the following list of icons with corresponding labels:
const icons = [
{ emoji: ‘🏠’, label: ‘Home’ },
{ emoji: ‘📧’, label: ‘Email’ },
{ emoji: ‘⚙️’, label: ‘Settings’ }
];
The tooltip should always display the value of the label field from this array, corresponding to the hovered icon.
Component Behavior
* Renders a list of icons (using emoji).
* Each icon has a text label shown only when hovered.
* Tooltip is positioned above the icon.
* Tooltip disappears when the mouse is no longer hovering over the icon.
* Only one tooltip should be visible at a time.
* Tooltip text must match exactly what’s defined in the Label property.
styles.css
.tooltip-container { display: flex; gap: 24px; font-size: 28px; padding: 50px; justify-content: center; } .tooltip-item { position: relative; text-align: center; cursor: pointer; transition: transform 0.2s ease; } .tooltip-item:hover { transform: scale(1.1); } .tooltip-box { position: absolute; bottom: 130%; left: 50%; transform: translateX(-50%); background: #222; color: #fff; padding: 6px 12px; border-radius: 6px; font-size: 14px; white-space: nowrap; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; animation: fadeIn 0.3s forwards; } @keyframes fadeIn { to { opacity: 1; } }
Tooltip.js
import React, { Component } from 'react'; import './styles.css'; class Tooltip extends Component { render() { const icons = [ { emoji: '🏠', label: 'Home' }, { emoji: '📧', label: 'Email' }, { emoji: '⚙️', label: 'Settings' } ]; return ( <div className="tooltip-container"> {icons.map((icon, index) => ( <div key={index} className="tooltip-item" > <span>{icon.emoji}</span> </div> ))} </div> ); } } export default Tooltip;
App.js
import Tooltip from './Tooltip' export default function App() { return <Tooltip/> }
https://namastedev.com/practice/tooltip
styles.css
.tooltip-container { display: flex; gap: 24px; font-size: 28px; padding: 50px; justify-content: center; } .tooltip-item { position: relative; text-align: center; cursor: pointer; transition: transform 0.2s ease; } .tooltip-item:hover { transform: scale(1.1); } .tooltip-box { position: absolute; bottom: 130%; left: 50%; transform: translateX(-50%); background: #222; color: #fff; padding: 6px 12px; border-radius: 6px; font-size: 14px; white-space: nowrap; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; animation: fadeIn 0.3s forwards; } @keyframes fadeIn { to { opacity: 1; } }
Tooltip.js
import React, { Component } from 'react'; import './styles.css'; class Tooltip extends Component { render() { const icons = [ { emoji: '🏠', label: 'Home' }, { emoji: '📧', label: 'Email' }, { emoji: '⚙️', label: 'Settings' } ]; return ( <div className="tooltip-container"> {icons.map((icon, index) => ( <div key={index} className="tooltip-item" > <span>{icon.emoji}</span> </div> ))} </div> ); } } export default Tooltip;
App.js
import Tooltip from './Tooltip' export default function App() { return <Tooltip/> }
Hook based implementation
import React, { useState } from 'react'; import './styles.css'; const icons = [ { emoji: '🏠', label: 'Home' }, { emoji: '📧', label: 'Email' }, { emoji: '⚙️', label: 'Settings' } ]; export default function Tooltip() { const [hoveredIndex, setHoveredIndex] = useState(null); return ( <div className="tooltip-container"> {icons.map((icon, index) => ( <div key={index} className="tooltip-item" onMouseEnter={() => setHoveredIndex(index)} onMouseLeave={() => setHoveredIndex(null)} > <span>{icon.emoji}</span> {hoveredIndex === index && ( <div className="tooltip-box">{icon.label}</div> )} </div> ))} </div> ); }
Authentication
Description
Build a simple user authentication system using React Context API. The goal is to understand how to create context, provide context, and consume context within your components, as well as manage basic authentication state globally.
Requirements:
1. UserContext:
Create a UserContext using
React. createContext().
Store the following in the context:
isLoggedIn: A boolean that is false by default, and it toggles between true and false using the login and logout functions.
login(): function to log in a user. logout (): function to log out the user.
2. App: Wrap the app with UserProvider.
3. Navbar Component:
* Displays the app title (App) in the navigation bar.
* Uses UserContext to access isLoggedIn, login, and logout.
* If the user is not logged in:
Shows a “Login” button that triggers the login function when clicked.
* If the user is logged in:
Shows a “Welcome, User!” message.
Displays a “Logout” button that triggers the logout function when clicked.
4. Dashboard Component:
* Uses UserContext to access the isLoggedin state.
* If the user is not logged in:
Displays a message: “Please login to access your dashboard”.
* If the user is logged in:
Displays the message: “This is your dashboard”.
styles.css
/* index.css or App.css */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f0f2f5; color: #333; height: 100vh; display: flex; justify-content: center; align-items: center; } .app { width: 400px; background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); overflow: hidden; } nav { background-color: #4a90e2; color: white; padding: 16px 24px; display: flex; justify-content: space-between; align-items: center; } nav h1 { font-size: 20px; } nav span { font-size: 14px; margin-right: 10px; } nav button { background-color: white; color: #4a90e2; border: none; padding: 6px 12px; border-radius: 4px; font-weight: bold; cursor: pointer; transition: background-color 0.3s ease; } nav button:hover { background-color: #e0eaff; } .dashboard { padding: 40px 20px; text-align: center; } .dashboard h2 { font-size: 18px; color: #333; }
App.js
import React from 'react'; import { UserProvider } from './userContext'; import Navbar from './Navbar'; import Dashboard from './Dashboard'; const App = () => { return ( <UserProvider> <div className="app"> <Navbar /> <Dashboard /> </div> </UserProvider> ); }; export default App;
userContext.js
import React, { createContext, useState } from 'react'; // Create the context const UserContext = createContext(); // Create a provider component const UserProvider = ({ children }) => { return ( <UserContext.Provider value={{}}> {children} </UserContext.Provider> ); }; export { UserContext, UserProvider };
Navbar.js
import React, { useContext } from 'react'; import { UserContext } from './userContext'; const Navbar = () => { return ( <nav> <h1>App</h1> </nav> ); }; export default Navbar;
Dashboard.js
import React, { useContext } from 'react'; import { UserContext } from './userContext'; const Dashboard = () => { return ( <div className="dashboard"> </div> ); }; export default Dashboard;
https://namastedev.com/practice/authentication
styles.css
/* index.css or App.css */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f0f2f5; color: #333; height: 100vh; display: flex; justify-content: center; align-items: center; } .app { width: 400px; background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); overflow: hidden; } nav { background-color: #4a90e2; color: white; padding: 16px 24px; display: flex; justify-content: space-between; align-items: center; } nav h1 { font-size: 20px; } nav span { font-size: 14px; margin-right: 10px; } nav button { background-color: white; color: #4a90e2; border: none; padding: 6px 12px; border-radius: 4px; font-weight: bold; cursor: pointer; transition: background-color 0.3s ease; } nav button:hover { background-color: #e0eaff; } .dashboard { padding: 40px 20px; text-align: center; } .dashboard h2 { font-size: 18px; color: #333; }
App.js
import React from 'react'; import { UserProvider } from './userContext'; import Navbar from './Navbar'; import Dashboard from './Dashboard'; const App = () => { return ( <UserProvider> <div className="app"> <Navbar /> <Dashboard /> </div> </UserProvider> ); }; export default App;
userContext.js
import React, { createContext, useState } from 'react'; // Create the context const UserContext = createContext(); // Create a provider component const UserProvider = ({ children }) => { const [isLoggedIn, setIsLoggedIn] = useState(false); const login = () => setIsLoggedIn(true); const logout = () => setIsLoggedIn(false); return ( <UserContext.Provider value={{ isLoggedIn, login, logout }}> {children} </UserContext.Provider> ); }; export { UserContext, UserProvider };
Navbar.js
import React, { useContext } from 'react'; import { UserContext } from './userContext'; const Navbar = () => { const { isLoggedIn, login, logout } = useContext(UserContext); return ( <nav> <h1>App</h1> <div> {!isLoggedIn ? ( <button onClick={login}>Login</button> ) : ( <> <span>Welcome, User!</span> <button onClick={logout}>Logout</button> </> )} </div> </nav> ); }; export default Navbar;
Dashboard.js
import React, { useContext } from 'react'; import { UserContext } from './userContext'; const Dashboard = () => { const { isLoggedIn } = useContext(UserContext); return ( <div className="dashboard"> <h2> {isLoggedIn ? 'This is your dashboard' : 'Please login to access your dashboard'} </h2> </div> ); }; export default Dashboard;
usePreviousHook
Description
You have to build a simple Counter App in React that also shows the previous count value. The goal is to allow users to increase, decrease, or reset the counter using buttons. In addition to displaying the current count, the app should also show the previous count using a custom usePrevious hook.
Things To Do
State Management
Use the useState hook to keep track of the current count value.const currentCount, setCurrentCount] = useState(0);
The initial value of the count should be 0.
Previous State Hook
Create a custom hook usePrevious to store the previous value of the count.
The hook should return undefined on the first render, and return the previous value after each update.const previousCount = usePrevious (currentCount);
Button Functionality
* Implement the increment function to increase the count by 1.
* The button should be labeled Increment.
* Implement the decrement function to decrease the count by 1.
* The button should be labeled Decrement.
* Implement the reset function to set the count back to 0.
* The button should be labeled Reset.
Display Output
Show the current count inside a heading element:Current Count: {currentCount)
Show the previous count (using the usePrevious hook) in a separate heading element:Previous Count: {previousCount)
App.js
import Counter from './Counter'; import './styles.css'; export default function App() { return <Counter />; }
usePrevious.js
import { useEffect, useRef } from "react"; export default function usePrevious() { }
Counter.js
import "./styles.css"; import { useState } from "react"; import usePrevious from "./usePrevious"; export default function Counter() { const previousCount = usePrevious(); return ( <div className="App"> <h2>Current Count:</h2> <h2>Previous Count:</h2> <button>Decrement</button> <button>Reset</button> <button>Increment</button> </div> ); }
App.js
import Counter from './Counter'; import './styles.css'; export default function App() { return <Counter />; }
usePrevious.js
import { useEffect, useRef } from "react"; export default function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); return ref.current; }
Counter.js
import "./styles.css"; import { useState } from "react"; import usePrevious from "./usePrevious"; export default function Counter() { const [currentCount, setCurrentCount] = useState(0); const previousCount = usePrevious(currentCount); const increment = () => setCurrentCount(prev => prev + 1); const decrement = () => setCurrentCount(prev => prev - 1); const reset = () => setCurrentCount(0); return ( <div className="App"> <h2>Current Count: {currentCount}</h2> <h2>Previous Count: {previousCount !== undefined ? previousCount : 'N/A'}</h2> <button onClick={decrement}>Decrement</button> <button onClick={reset}>Reset</button> <button onClick={increment}>Increment</button> </div> ); }
styles.css
.App { font-family: sans-serif; text-align: center; margin-top: 50px; } button { margin: 10px; padding: 10px 20px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; transition: background-color 0.2s ease; } button:hover { background-color: #f0f0f0; }
Accordion
Description
Build a React Accordion component that allows users to expand and collapse sections of content. When a section is clicked, it should toggle its visibility. If a new section is clicked, it should expand while the others collapse (i.e., only one section is open at a time).
Requirements
1. Display a list of accordion items, each with a title and content.
2. Clicking on a title expands its content and collapses any previously opened item.
3. If an already open inm is clicked, it should collapse.
4. The component should accept an array of items as props. Each item contains:
title: The heading of the accordion item. content: The details inside the accordion item.
5. The component should handle edge cases such as an empty list or invalid input by displaying a message “No items available”.
Constraints & Edge Cases
* The items prop should be an array of objects f title: string, content: string }.
* If items is empty, display a message like “No items available.”
* Optimize performance by using React’s useState and conditional rendering.
styles.css
/* General Accordion Styles */ .accordion { width: 100%; max-width: 400px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background-color: #f9f9f9; } /* Accordion Item Styles */ .accordion-item { margin-bottom: 10px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; } /* Accordion Title Button */ .accordion-title { width: 100%; padding: 15px; text-align: left; background-color: #f1f1f1; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold; transition: background-color 0.3s ease; } .accordion-title:hover { background-color: #e0e0e0; } .accordion-title[aria-expanded="true"] { background-color: #d0d0d0; } .accordion-content { padding: 15px; background-color: #fafafa; border-top: 1px solid #ddd; font-size: 14px; } .accordion p { font-size: 16px; color: #666; text-align: center; }
Accordion.js
import React, { useState } from "react"; import { FaChevronDown, FaChevronUp } from "react-icons/fa"; import './styles.css' function Accordion({ items }) { return ( <div> </div> ); } export default Accordion;
App.js
import Accordion from "./Accordion" export default function App() { const items = [ { title: "JavaScript Basics", content: "Learn variables, functions, and loops in JavaScript." }, { title: "React.js Overview", content: "Understand components, state, and props in React." }, { title: "Node.js", content: "Basics of server-side development with Node.js." }, { title: "Full-Stack Development", content: "Build full-stack apps with React and Node.js." }, ]; return <Accordion items={items}/> }
https://namastedev.com/practice/accordion
styles.css
/* General Accordion Styles */ .accordion { width: 100%; max-width: 400px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background-color: #f9f9f9; } /* Accordion Item Styles */ .accordion-item { margin-bottom: 10px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; } /* Accordion Title Button */ .accordion-title { width: 100%; padding: 15px; text-align: left; background-color: #f1f1f1; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold; transition: background-color 0.3s ease; } .accordion-title:hover { background-color: #e0e0e0; } .accordion-title[aria-expanded="true"] { background-color: #d0d0d0; } .accordion-content { padding: 15px; background-color: #fafafa; border-top: 1px solid #ddd; font-size: 14px; } .accordion p { font-size: 16px; color: #666; text-align: center; }
Accordion.js
import React, { useState } from "react"; import { FaChevronDown, FaChevronUp } from "react-icons/fa"; import "./styles.css"; function Accordion({ items }) { const [activeIndex, setActiveIndex] = useState(null); if (!Array.isArray(items) || items.length === 0) { return ( <div className="accordion"> <p>No items available</p> </div> ); } const toggleIndex = (index) => { setActiveIndex((prevIndex) => (prevIndex === index ? null : index)); }; return ( <div className="accordion"> {items.map((item, index) => { const isOpen = activeIndex === index; return ( <div key={index} className="accordion-item"> <button className="accordion-title" onClick={() => toggleIndex(index)} aria-expanded={isOpen} > {item.title} <span style={{ float: "right" }}> {isOpen ? <FaChevronUp /> : <FaChevronDown />} </span> </button> {isOpen && ( <div className="accordion-content"> {item.content} </div> )} </div> ); })} </div> ); } export default Accordion;
App.js
import Accordion from "./Accordion" export default function App() { const items = [ { title: "JavaScript Basics", content: "Learn variables, functions, and loops in JavaScript." }, { title: "React.js Overview", content: "Understand components, state, and props in React." }, { title: "Node.js", content: "Basics of server-side development with Node.js." }, { title: "Full-Stack Development", content: "Build full-stack apps with React and Node.js." }, ]; return <Accordion items={items}/> }
Dark Mode
You have to build a simple Dark Mode Toggle component in React. The goal is to allow users to switch between light mode and dark mode by toggling a checkbox. The theme should visually update the background color, text and text color *
Things To Do
1. State Management
Add a useState hook to keep track of whether the app is in dark mode or light mode.
2. Toggle Function
Implement the togg leTheme function to update the state when the checkbox is toggled.
3. Dynamic Class Application
Apply the class dark-mode or light-mode to the parent ‹ div> based on the value of state variable.
4. Text Label
Update the ‹span className=”mode-text”> to show “Dark Mode” or
“Light Mode” depending on
the current theme.
Important Note
* Apply the class dark-mode to the parent < div> when dark mode is active.
* Apply the class light-mode when light mode is active.
style.css
body { margin: 0; } /* Light Mode */ .light-mode { background-color: #f0f0f0; color: #333; } /* Dark Mode */ .dark-mode { background-color: #121212; color: white; } .container { text-align: center; height: 100vh; width: 100vw; display: flex; flex-direction: column; justify-content: center; align-items: center; } h1 { font-size: 32px; margin-bottom: 30px; } .toggle-container { display: flex; justify-content: center; align-items: center; gap: 20px; } .mode-text { font-size: 18px; font-weight: bold; color: inherit; } /* Toggle switch styles */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: 0.4s; border-radius: 50px; } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; border-radius: 50px; left: 4px; bottom: 4px; background-color: white; transition: 0.4s; } input:checked + .slider { background-color: #4caf50; } input:checked + .slider:before { transform: translateX(26px); }
App.js
import DarkModeToggle from './DarkModeToggle' export default function App() { return <DarkModeToggle/> }
DarkModeToggle.js
import React, { useEffect, useState } from 'react'; import './styles.css' function DarkModeToggle() { return ( <div className={`container`}> <h1>Dark Mode Toggle</h1> <div className="toggle-container"> <label className="switch"> <input type="checkbox" /> <span className="slider round"></span> </label> <span className="mode-text"></span> </div> </div> ); } export default DarkModeToggle;
https://namastedev.com/practice/dark-mode
style.css
body { margin: 0; } /* Light Mode */ .light-mode { background-color: #f0f0f0; color: #333; } /* Dark Mode */ .dark-mode { background-color: #121212; color: white; } .container { text-align: center; height: 100vh; width: 100vw; display: flex; flex-direction: column; justify-content: center; align-items: center; } h1 { font-size: 32px; margin-bottom: 30px; } .toggle-container { display: flex; justify-content: center; align-items: center; gap: 20px; } .mode-text { font-size: 18px; font-weight: bold; color: inherit; } /* Toggle switch styles */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: 0.4s; border-radius: 50px; } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; border-radius: 50px; left: 4px; bottom: 4px; background-color: white; transition: 0.4s; } input:checked + .slider { background-color: #4caf50; } input:checked + .slider:before { transform: translateX(26px); }
App.js
import DarkModeToggle from './DarkModeToggle' export default function App() { return <DarkModeToggle/> }
DarkModeToggle.js
import React, { useState } from 'react'; import './styles.css'; function DarkModeToggle() { const [isDarkMode, setIsDarkMode] = useState(false); const toggleTheme = () => { setIsDarkMode((prevMode) => !prevMode); }; return ( <div className={`container ${isDarkMode ? 'dark-mode' : 'light-mode'}`}> <h1>Dark Mode Toggle</h1> <div className="toggle-container"> <label className="switch"> <input type="checkbox" onChange={toggleTheme} checked={isDarkMode} /> <span className="slider"></span> </label> <span className="mode-text"> {isDarkMode ? 'Dark Mode' : 'Light Mode'} </span> </div> </div> ); } export default DarkModeToggle;
Sidebar
Description
Create a React sidebar component that can be toggled open or closed with a menu button. The sidebar appears on the right side of the screen and includes navigation items with hover effects.
Requirements
* The interface must include:
A sidebar positioned on the right side of the viewport.
A toggle button (with a menu icon) that is always visible and vertically centered on the right edge of the screen.
Use “Menu” icon form lucide-react
* Default Behavior:
The sidebar is hidden by defantlt.
The toggle button remains fixed and accessible at all times.
* Toggle Functionality:
Clicking the toggle button opens or closes the sidebar.
The sidebar should slide in and out from the right with a smooth transition effect.
* Sidebar Content:
When open, the sidebar displays a vertical list of navigation items:
Home
About
Services
Contact
Each navigation item should have a clear and smooth hover effect for better user interaction.
Data Test IDs (required for testing):
* data-testid=”sidebar” - sidebar container div
* data-testid=”btn-toggle” - toggle button
element
* data-testid=”icon-menu” - menu icon inside toggle button
* data-testid=”nav-menu” - container for nav items when sidebar is open
* data-testid=”nav-item-home” - nav item Home
* data-testid=”nav-item-about” - nav item About
* data-testid=”nav-item-services” - nav item
Services
* data-testid=”nav-item-contact” - nav item
Contact
styles.css
/* Container for sidebar */ .sidebar { position: fixed; right: 0; /* changed from left: 0 */ height: 100vh; width: 280px; background: linear-gradient(135deg, #4b6cb7, #182848); color: #f0f0f5; box-shadow: -2px 0 12px rgba(0, 0, 0, 0.3); padding-top: 60px; transform: translateX(100%); transition: transform 0.35s ease, box-shadow 0.3s ease; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; z-index: 1000; } /* Sidebar visible */ .sidebar.open { transform: translateX(0); box-shadow: -4px 0 20px rgba(0, 0, 0, 0.5); } /* Toggle button */ .toggle-btn { position: absolute; top: 15px; left: -60px; background-color: #4b6cb7; border: none; border-radius: 50%; padding: 12px; cursor: pointer; color: #f0f0f5; box-shadow: 0 4px 8px rgba(75, 108, 183, 0.6); transition: background-color 0.3s ease, transform 0.25s ease; display: flex; align-items: center; justify-content: center; } .toggle-btn:hover { background-color: #182848; transform: scale(1.1); } /* Navigation menu */ .nav-menu { width: 100%; } .nav-list { list-style: none; padding: 0 20px; margin: 0; } .nav-item { padding: 15px 20px; margin: 8px 0; border-radius: 8px; font-weight: 600; font-size: 1.1rem; cursor: pointer; color: #f0f0f5; transition: all 0.3s ease; user-select: none; position: relative; overflow: hidden; } .nav-item::after { content: ""; position: absolute; bottom: 8px; left: 20px; height: 2px; width: 0%; background: #a8c0ff; transition: width 0.3s ease; border-radius: 2px; } .nav-item:hover::after { width: 60%; } .nav-item:hover { color: #ffffff; text-shadow: 0 0 5px #a8c0ff; }
Sidebar.js
import React from "react"; import "./styles.css"; function Sidebar() { return ( <div className="sidebar"> <button className="toggle-btn">{/* Icon goes here */}</button> <nav className="nav-menu"> <ul className="nav-list"> <li className="nav-item"></li> <li className="nav-item"></li> <li className="nav-item"></li> <li className="nav-item"></li> </ul> </nav> </div> ); } export default Sidebar;
App.js
import Sidebar from './Sidebar.js' export default function App() { return <Sidebar/> }
https://namastedev.com/practice/sidebar
styles.css
/* Container for sidebar */ .sidebar { position: fixed; right: 0; /* changed from left: 0 */ height: 100vh; width: 280px; background: linear-gradient(135deg, #4b6cb7, #182848); color: #f0f0f5; box-shadow: -2px 0 12px rgba(0, 0, 0, 0.3); padding-top: 60px; transform: translateX(100%); transition: transform 0.35s ease, box-shadow 0.3s ease; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; z-index: 1000; } /* Sidebar visible */ .sidebar.open { transform: translateX(0); box-shadow: -4px 0 20px rgba(0, 0, 0, 0.5); } /* Toggle button */ .toggle-btn { position: absolute; top: 15px; left: -60px; background-color: #4b6cb7; border: none; border-radius: 50%; padding: 12px; cursor: pointer; color: #f0f0f5; box-shadow: 0 4px 8px rgba(75, 108, 183, 0.6); transition: background-color 0.3s ease, transform 0.25s ease; display: flex; align-items: center; justify-content: center; } .toggle-btn:hover { background-color: #182848; transform: scale(1.1); } /* Navigation menu */ .nav-menu { width: 100%; } .nav-list { list-style: none; padding: 0 20px; margin: 0; } .nav-item { padding: 15px 20px; margin: 8px 0; border-radius: 8px; font-weight: 600; font-size: 1.1rem; cursor: pointer; color: #f0f0f5; transition: all 0.3s ease; user-select: none; position: relative; overflow: hidden; } .nav-item::after { content: ""; position: absolute; bottom: 8px; left: 20px; height: 2px; width: 0%; background: #a8c0ff; transition: width 0.3s ease; border-radius: 2px; } .nav-item:hover::after { width: 60%; } .nav-item:hover { color: #ffffff; text-shadow: 0 0 5px #a8c0ff; }
Sidebar.js
import React, { useState } from "react"; import { Menu } from "lucide-react"; import "./styles.css"; function Sidebar() { const [isOpen, setIsOpen] = useState(false); const toggleSidebar = () => { setIsOpen((prev) => !prev); }; return ( <div className={`sidebar ${isOpen ? "open" : ""}`} data-testid="sidebar" > <button className="toggle-btn" onClick={toggleSidebar} data-testid="btn-toggle" > <Menu size={24} data-testid="icon-menu" /> </button> {isOpen && ( <nav className="nav-menu" data-testid="nav-menu"> <ul className="nav-list"> <li className="nav-item" data-testid="nav-item-home"> Home </li> <li className="nav-item" data-testid="nav-item-about"> About </li> <li className="nav-item" data-testid="nav-item-services"> Services </li> <li className="nav-item" data-testid="nav-item-contact"> Contact </li> </ul> </nav> )} </div> ); } export default Sidebar;
App.js
import Sidebar from './Sidebar.js' export default function App() { return <Sidebar/> }
Mortgage Calculator
Description:
Create a Mortgage Calculator in React that allows users to input loan amount, interest rate, and loan term (years) to calculate the monthly mortgage payment.
Requirements
* Must have Input fields for:
Loan amount (in INR) with label=”Loan Amount” Annual interest rate (in %) with label=”Annual Interest Rate”
Loan term (in years) with id=”Loan Term”
* Show message “Invalid input” for inappropriate inputs
* Must have a button labelled “Calculate” to calculate the monthly payment
* Calculate monthly payment using the formula:
M = P x ((r (1 +r)^n)/(((1 + r)^n) - 1))
where:
M = monthly payment
P = loan principal (loan amount)
r = monthly interest rate = annual rate / 12 / 100
n = number of monthly payments = years * 12
* Display the calculated monthly payment.
* The result (monthly payment) must have aria-label=“result”
Constraints & Edge Cases
* Inputs should be non-negative numbers.
* Interest rate cannot be zero or negative.
* Term should be greater than 0 years.
* Monthly payment should be displayed only if inputs are valid.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
MortageCalculator.js
import React from "react"; import './styles.css' function MortgageCalculator() { return ( <div> {/* Implement Mortgage Calculator logic here */} </div> ); } export default MortgageCalculator;
App.js
import MortgageCalculator from "./MortgageCalculator"; export default function App() { return <MortgageCalculator />; }
https://namastedev.com/practice/mortgage-calculator
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
MortageCalculator.js
import React, { useState } from "react"; import "./styles.css"; function MortgageCalculator() { const [amount, setAmount] = useState(""); const [interest, setInterest] = useState(""); const [term, setTerm] = useState(""); const [result, setResult] = useState(null); const [error, setError] = useState(""); const calculatePayment = () => { const P = parseFloat(amount); const annualRate = parseFloat(interest); const years = parseFloat(term); // Input validations if ( isNaN(P) || P < 0 || isNaN(annualRate) || annualRate <= 0 || isNaN(years) || years <= 0 ) { setError("Invalid input"); setResult(null); return; } setError(""); const r = annualRate / 12 / 100; const n = years * 12; const M = P * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1); setResult(M.toFixed(2)); }; return ( <div> <h1>Mortgage Calculator</h1> <div> <label> Loan Amount <input type="number" value={amount} onChange={(e) => setAmount(e.target.value)} /> </label> </div> <div> <label> Annual Interest Rate <input type="number" value={interest} onChange={(e) => setInterest(e.target.value)} /> </label> </div> <div> <label> Loan Term <input type="number" id="Loan Term" value={term} onChange={(e) => setTerm(e.target.value)} /> </label> </div> <button onClick={calculatePayment}>Calculate</button> {error && <p style={{ color: "red" }}>{error}</p>} {result && ( <p aria-label="result"> Monthly Payment: ₹{result} </p> )} </div> ); } export default MortgageCalculator;
App.js
import MortgageCalculator from "./MortgageCalculator"; export default function App() { return <MortgageCalculator />; }
Even or Odd
Description:
Create a React component that allows users to input a number and checks whether the number is even or odd. The component displays the result with a 1-second loading delay and handles invalid inputs.
Requirements
* A user can enter a number in an input field.
The input box should have a placeholder “Enter a number”
* A button is provided to initiate the check.
* Upon clicking the button:
Any previous result should be cleared immediately.
A loading indicator should appear for 1 second to simulate processing.
In that one second a label “Checking…” should appear in the result-area.
After the delay, the result should display in the format:
“The number X is even.”
“The number X is odd.”
* If the input is empty or not a valid number:
Show a clear error message such as: “Please enter a valid number.”
Edge Cases & Constraints:
* Non-numeric input should display “Please enter a valid number.”
* Empty input should be handled gracefully.
* Leading/trailing spaces should be ignored.
* Large numbers should be processed correctly
* Loading message “Checking…” should be shown before result.
* The result display must only appear after loading completes.
Example Inputs & Outputs
// Example 1: Even number
Input: “4”
Output: “The number 4 is even.”
// Example 2: Odd number
Input: “5”
Output: “The number 5 is odd.”
// Example 3: Invalid input
Input: “abc”
Output: “Please enter a valid number.”
Data Test IDs (required for testing):
* data-testid=”number-input”: The input field for entering number
* data-testid=”check-button”: The button to trigger checking with the text “check”
* data-testid=”loading”: Element showing loading text
* data-testid=”result”: Element displaying the result or error message
styles.css
body { margin: 0; padding: 0; font-family: "Poppins", sans-serif; background: linear-gradient(135deg, #e0c3fc, #8ec5fc); height: 100vh; display: flex; justify-content: center; align-items: center; } /* Container */ .even-odd-container { background: rgba(255, 255, 255, 0.2); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-radius: 20px; padding: 2rem 3rem; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); text-align: center; width: 360px; height: 250px; } .even-odd-container:hover { transform: scale(1.02); } /* Heading */ .title { font-size: 2rem; font-weight: 600; color: #040539; margin-bottom: 1.5rem; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } /* Input */ .number-input { width: 90%; padding: 0.8rem 1rem; font-size: 0.8rem; border: none; border-radius: 12px; margin-bottom: 1.2rem; background-color: rgba(255, 255, 255, 0.3); color: #333; backdrop-filter: blur(6px); outline: none; } .number-input::placeholder { color: #555; } .number-input:focus { background-color: rgba(255, 255, 255, 0.6); } /* Button */ .check-button { padding: 0.75rem 2rem; font-size: 1rem; font-weight: 600; color: white; background: linear-gradient(135deg, #667eea, #764ba2); border: none; border-radius: 30px; cursor: pointer; transition: background 0.3s ease; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2); margin-bottom: 1rem; } .check-button:hover { background: linear-gradient(135deg, #5a67d8, #6b46c1); } /* Result Area */ .result-area { display: flex; justify-content: center; align-items: center; min-height: 2rem; } /* Loading Text */ .loading { font-size: 1rem; font-style: italic; color: #938cb4; } /* Final Result Text */ .result { margin-top: 1rem; font-size: 1.1rem; font-weight: 500; color: #0c013f; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); }
EvenorOdd.js
import React from "react"; import "./styles.css"; function EvenOrOddChecker() { return ( <div className="even-odd-container"> <h1 className="title">Even or Odd Checker</h1> <input className="number-input" type="text" placeholder="Enter a number" /> <button className="check-button">Check</button> <div className="result-area"> <div className="result">Result appears here</div> </div> </div> ); } export default EvenOrOddChecker;
App.js
import EvenOrOdd from './EvenOrOdd' export default function App() { return <EvenOrOdd/> }
https://namastedev.com/practice/even-or-odd
styles.css
body { margin: 0; padding: 0; font-family: "Poppins", sans-serif; background: linear-gradient(135deg, #e0c3fc, #8ec5fc); height: 100vh; display: flex; justify-content: center; align-items: center; } /* Container */ .even-odd-container { background: rgba(255, 255, 255, 0.2); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-radius: 20px; padding: 2rem 3rem; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); text-align: center; width: 360px; height: 250px; } .even-odd-container:hover { transform: scale(1.02); } /* Heading */ .title { font-size: 2rem; font-weight: 600; color: #040539; margin-bottom: 1.5rem; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } /* Input */ .number-input { width: 90%; padding: 0.8rem 1rem; font-size: 0.8rem; border: none; border-radius: 12px; margin-bottom: 1.2rem; background-color: rgba(255, 255, 255, 0.3); color: #333; backdrop-filter: blur(6px); outline: none; } .number-input::placeholder { color: #555; } .number-input:focus { background-color: rgba(255, 255, 255, 0.6); } /* Button */ .check-button { padding: 0.75rem 2rem; font-size: 1rem; font-weight: 600; color: white; background: linear-gradient(135deg, #667eea, #764ba2); border: none; border-radius: 30px; cursor: pointer; transition: background 0.3s ease; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2); margin-bottom: 1rem; } .check-button:hover { background: linear-gradient(135deg, #5a67d8, #6b46c1); } /* Result Area */ .result-area { display: flex; justify-content: center; align-items: center; min-height: 2rem; } /* Loading Text */ .loading { font-size: 1rem; font-style: italic; color: #938cb4; } /* Final Result Text */ .result { margin-top: 1rem; font-size: 1.1rem; font-weight: 500; color: #0c013f; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); }
EvenorOdd.js
import React, { useState } from "react"; import "./styles.css"; function EvenOrOddChecker() { const [inputValue, setInputValue] = useState(""); const [result, setResult] = useState(""); const [loading, setLoading] = useState(false); const handleCheck = () => { const trimmed = inputValue.trim(); // Clear previous result immediately setResult(""); setLoading(true); // Validate input if (trimmed === "" || isNaN(trimmed)) { setLoading(false); setResult("Please enter a valid number."); return; } // Simulate 1-second processing delay setTimeout(() => { setLoading(false); const number = Number(trimmed); const isEven = number % 2 === 0; setResult(`The number ${number} is ${isEven ? "even" : "odd"}.`); }, 1000); }; return ( <div className="even-odd-container"> <h1 className="title">Even or Odd Checker</h1> <input className="number-input" type="text" placeholder="Enter a number" data-testid="number-input" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <button className="check-button" data-testid="check-button" onClick={handleCheck} > Check </button> <div className="result-area"> {loading ? ( <div className="loading" data-testid="loading">Checking...</div> ) : ( result && ( <div className="result" data-testid="result">{result}</div> ) )} </div> </div> ); } export default EvenOrOddChecker;
App.js
import EvenOrOdd from './EvenOrOdd' export default function App() { return <EvenOrOdd/> }
Filter Recipes
Description:
You are tasked with creating a simple recipe filter and cart system. You will be given a list of recipes (with information like name, rating, cuisine, and image), and you need to build a component that allows users to filter recipes by rating, view the average rating of the filtered recipes, and add recipes to a shopping cart.
Requirements:
1. Recipe Filter:
You need to filter recipes based on a rating threshold.
Users should be able to select a minimum rating from a dropdown (with the options: 4. 0+, 4.3+, 4.5+, 4.7+, and 4.9).
Only recipes with a rating greater than or equal to the selected rating should be displayed.
2. Cart System:
Each recipe displayed should have an “Add to Cart” button. When clicked, the recipe should be added to the cart.
The cart should show the number of items added.
There is no need to show the cart details, only the count of items in the cart.
3. Average Rating Calculation:
You need to calculate the average rating of the filtered recipes. The average should be displayed on the page.
If there are no recipes in the filtered list, show the average rating as 0.00.
**Functional Requirements **
1. Recipe Filter
* Provide a dropdown filter labeled “Filter by Rating:” .
* The dropdown should include the following options:
4.0+, 4.3+, 4.5+, 4.7+, and 4.9.
* Only recipes with a rating greater than or equal to the selected rating should be displayed.
2. Cart System
* Each recipe should include a clearly labeled “Add to Cart” button.
* Clicking the button should add the recipe to a cart and update the item count.
* The total number of items in the cart should be displayed in the format: “Cart Items: 0”, “Cart Items: 1”, etc.
* Cart details (like recipe names, do not need to be shown-only the count is required.
3. Average Rating
* The component should display the average rating of the currently filtered recipes.
* The average should be shown in two decimal places, e.g., Average Rating: 4.87.
* If no recipes match the selected rating filter, display:
Average Rating: 0.00.
styles.css
``` App.js
import “./styles.css”;
import RecipeFilterApp from “./RecipeFilterApp.js”;
export default function App() {
return <RecipeFilterApp></RecipeFilterApp>;
}
~~~
RecipeFilterApp.js
import React, { useState } from "react"; import "./styles.css"; const RecipeFilterApp = () => { return ( <div> <h1>🍽️ Recipe Explorer</h1> </div> ); }; export default RecipeFilterApp;
recipesData.js
export default recipesData = [ { id: 1, name: "Classic Margherita Pizza", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/1.webp", rating: 4.6, reviewCount: 98, }, { id: 2, name: "Vegetarian Stir-Fry", cuisine: "Asian", image: "https://cdn.dummyjson.com/recipe-images/2.webp", rating: 4.7, reviewCount: 26, }, { id: 3, name: "Chocolate Chip Cookies", cuisine: "American", image: "https://cdn.dummyjson.com/recipe-images/3.webp", rating: 4.9, reviewCount: 13, }, { id: 4, name: "Chicken Alfredo Pasta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/4.webp", rating: 4.9, reviewCount: 82, }, { id: 5, name: "Mango Salsa Chicken", cuisine: "Mexican", image: "https://cdn.dummyjson.com/recipe-images/5.webp", rating: 4.9, reviewCount: 63, }, { id: 6, name: "Quinoa Salad with Avocado", cuisine: "Mediterranean", image: "https://cdn.dummyjson.com/recipe-images/6.webp", rating: 4.4, reviewCount: 59, }, { id: 7, name: "Tomato Basil Bruschetta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/7.webp", rating: 4.7, reviewCount: 95, }, { id: 8, name: "Beef and Broccoli Stir-Fry", cuisine: "Asian", image: "https://cdn.dummyjson.com/recipe-images/8.webp", rating: 4.7, reviewCount: 58, }, { id: 9, name: "Caprese Salad", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/9.webp", rating: 4.6, reviewCount: 82, }, { id: 10, name: "Shrimp Scampi Pasta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/10.webp", rating: 4.3, reviewCount: 5, }, ];
https://namastedev.com/practice/filter-recipes
styles.css
.app-container { padding: 2rem; font-family: Arial, sans-serif; text-align: center; } .controls { margin-bottom: 1rem; } .summary { margin: 1rem 0; font-size: 1.1rem; } .recipes-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.5rem; margin-top: 1.5rem; } .recipe-card { background: #fdfdfd; padding: 1rem; border: 1px solid #ddd; border-radius: 12px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.07); } .recipe-img { width: 100%; height: 140px; object-fit: cover; border-radius: 8px; margin-bottom: 0.75rem; } .recipe-card button { padding: 0.5rem 1rem; margin-top: 0.5rem; background-color: #5cb85c; border: none; border-radius: 6px; color: white; font-weight: bold; cursor: pointer; } .recipe-card button:hover { background-color: #4cae4c; }
App.js
import "./styles.css"; import RecipeFilterApp from "./RecipeFilterApp.js"; export default function App() { return <RecipeFilterApp />; }
RecipeFilterApp.js
import React, { useState } from "react"; import recipesData from "./recipesData"; import "./styles.css"; const ratingOptions = [4.0, 4.3, 4.5, 4.7, 4.9]; const RecipeFilterApp = () => { const [minRating, setMinRating] = useState(4.0); const [cartCount, setCartCount] = useState(0); const filteredRecipes = recipesData.filter( (recipe) => recipe.rating >= minRating ); const averageRating = filteredRecipes.length ? ( filteredRecipes.reduce((sum, recipe) => sum + recipe.rating, 0) / filteredRecipes.length ).toFixed(2) : "0.00"; const handleAddToCart = () => { setCartCount((prev) => prev + 1); }; return ( <div className="app-container"> <h1>🍽️ Recipe Explorer</h1> <div className="controls"> <label htmlFor="rating-filter">Filter by Rating: </label> <select id="rating-filter" value={minRating} onChange={(e) => setMinRating(parseFloat(e.target.value))} > {ratingOptions.map((option) => ( <option key={option} value={option}> {option}+ </option> ))} </select> </div> <div className="summary"> <p><strong>Cart Items:</strong> {cartCount}</p> <p><strong>Average Rating:</strong> {averageRating}</p> </div> <div className="recipes-grid"> {filteredRecipes.map((recipe) => ( <div key={recipe.id} className="recipe-card"> <img src={recipe.image} alt={recipe.name} className="recipe-img" /> <h3>{recipe.name}</h3> <p>Cuisine: {recipe.cuisine}</p> <p>Rating: {recipe.rating} ⭐ ({recipe.reviewCount} reviews)</p> <button onClick={handleAddToCart}>Add to Cart</button> </div> ))} {filteredRecipes.length === 0 && <p>No recipes found for this rating.</p>} </div> </div> ); }; export default RecipeFilterApp;
recipesData.js
export default recipesData = [ { id: 1, name: "Classic Margherita Pizza", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/1.webp", rating: 4.6, reviewCount: 98, }, { id: 2, name: "Vegetarian Stir-Fry", cuisine: "Asian", image: "https://cdn.dummyjson.com/recipe-images/2.webp", rating: 4.7, reviewCount: 26, }, { id: 3, name: "Chocolate Chip Cookies", cuisine: "American", image: "https://cdn.dummyjson.com/recipe-images/3.webp", rating: 4.9, reviewCount: 13, }, { id: 4, name: "Chicken Alfredo Pasta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/4.webp", rating: 4.9, reviewCount: 82, }, { id: 5, name: "Mango Salsa Chicken", cuisine: "Mexican", image: "https://cdn.dummyjson.com/recipe-images/5.webp", rating: 4.9, reviewCount: 63, }, { id: 6, name: "Quinoa Salad with Avocado", cuisine: "Mediterranean", image: "https://cdn.dummyjson.com/recipe-images/6.webp", rating: 4.4, reviewCount: 59, }, { id: 7, name: "Tomato Basil Bruschetta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/7.webp", rating: 4.7, reviewCount: 95, }, { id: 8, name: "Beef and Broccoli Stir-Fry", cuisine: "Asian", image: "https://cdn.dummyjson.com/recipe-images/8.webp", rating: 4.7, reviewCount: 58, }, { id: 9, name: "Caprese Salad", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/9.webp", rating: 4.6, reviewCount: 82, }, { id: 10, name: "Shrimp Scampi Pasta", cuisine: "Italian", image: "https://cdn.dummyjson.com/recipe-images/10.webp", rating: 4.3, reviewCount: 5, }, ];
Focus Input
Description:
You are tasked with building a simple React component that demonstrates how to programmatically focus an input element using the useRef hook.
Create a functional component called InputFocus that:
* Renders a text input and a button.
* When the button is clicked, the input should automatically receive focus.
* Uses the useRef hook to reference ine input element directly and call . focus () on it.
Requirements:
1. Use the useRef hook to get a reference to the input element.
2. The input must have placeholder “Type here”.
3. The button must be labelled “Focus input”.
Example Behavior:
* On page load, the input is not focused.
* When the user clicks the “Focus Input” button, the text cursor appears inside the Input field, ready for typing.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
InputFocus.js
import React from 'react'; function InputFocus() { return ( <div style={{ padding: '20px', textAlign: 'center' }}> <input type="text" placeholder="Type here" style={{ padding: '8px', fontSize: '16px', marginRight: '10px' }} /> <button style={{ padding: '8px 12px' }}> Focus Input </button> </div> ); } export default InputFocus;
App.js
import InputFocus from './InputFocus' export default function App() { return <InputFocus/> }
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
InputFocus.js
import React, { useRef } from 'react'; function InputFocus() { const inputRef = useRef(null); // Step 1: create the ref const handleFocus = () => { if (inputRef.current) { inputRef.current.focus(); // Step 4: focus the input } }; return ( <div style={{ padding: '20px', textAlign: 'center' }}> <input ref={inputRef} // Step 3: attach the ref type="text" placeholder="Type here" style={{ padding: '8px', fontSize: '16px', marginRight: '10px' }} /> <button onClick={handleFocus} // Step 4: handle button click style={{ padding: '8px 12px' }} > Focus Input </button> </div> ); } export default InputFocus;
App.js
import InputFocus from './InputFocus' export default function App() { return <InputFocus/> }
Blog Post
Description:
You are building a blog Ul for a content platform. The platform stores a list of blog posts, each with a title, description (body). tags, views, and reactions (likes and dislikes).
Your task is to create a React application that displays this data in a clean, structured format using a reusable PostCard component for each blog post.
Functional Requirements:
1. Create a component named PostCard that accepts the following props:
title (string)
body (string)
tags (array of strings)
reactions (object with Likes angdis likes)
views (number)
2. Each card should:
Display the title and body.
Display the number of likes 👍 dislikes 👎, and total views 👁️.
3. You are provided with the blog post data in a separate file named postData.js. Your application should import this data and display the posts accordingly.
styles.css
``` App.js
import “./styles.css”;
import BlogPosts from “./BlogPosts.js”;
export default function App() {
return <BlogPosts></BlogPosts>;
}
~~~
PostsData.js
// postsData.js export default [ { id: 1, title: "His mother had always taught him", body: "His mother had always taught him not to ever think of himself as better than others...", tags: ["history", "american", "crime"], reactions: { likes: 192, dislikes: 25 }, views: 305, userId: 121, }, { id: 2, title: "He was an expert but not in a discipline", body: "He was an expert but not in a discipline that anyone could fully appreciate...", tags: ["french", "fiction", "english"], reactions: { likes: 859, dislikes: 32 }, views: 4884, userId: 91, }, { id: 3, title: "Dave watched as the forest burned up on the hill.", body: "Dave watched as the forest burned up on the hill, only a few miles from her house. The car had been hastily packed and Marta was inside trying to round up the last of the pets. Dave went through his mental list of the most important papers and documents that they couldn't leave behind. He scolded himself for not having prepared these better in advance and hoped that he had remembered everything that was needed. He continued to wait for Marta to appear with the pets, but she still was nowhere to be seen.", tags: ["magical", "history", "french"], reactions: { likes: 1448, dislikes: 39, }, views: 4152, userId: 16, }, { id: 4, title: "All he wanted was a candy bar.", body: "All he wanted was a candy bar. It didn't seem like a difficult request to comprehend, but the clerk remained frozen and didn't seem to want to honor the request. It might have had something to do with the gun pointed at his face.", tags: ["mystery", "english", "american"], reactions: { likes: 359, dislikes: 18, }, views: 4548, userId: 47, }, { id: 5, title: "Hopes and dreams were dashed that day.", body: "Hopes and dreams were dashed that day. It should have been expected, but it still came as a shock. The warning signs had been ignored in favor of the possibility, however remote, that it could actually happen. That possibility had grown from hope to an undeniable belief it must be destiny. That was until it wasn't and the hopes and dreams came crashing down.", tags: ["crime", "mystery", "love"], reactions: { likes: 119, dislikes: 30, }, views: 626, userId: 131, }, { id: 6, title: "Dave wasn't exactly sure how he had ended up", body: "Dave wasn't exactly sure how he had ended up in this predicament. He ran through all the events that had lead to this current situation and it still didn't make sense. He wanted to spend some time to try and make sense of it all, but he had higher priorities at the moment. The first was how to get out of his current situation of being naked in a tree with snow falling all around and no way for him to get down.", tags: ["english", "classic", "american"], reactions: { likes: 15, dislikes: 8, }, views: 38, userId: 98, }, { id: 7, title: "This is important to remember.", body: "This is important to remember. Love isn't like pie. You don't need to divide it among all your friends and loved ones. No matter how much love you give, you can always give more. It doesn't run out, so don't try to hold back giving it as if it may one day run out. Give it freely and as much as you want.", tags: ["magical", "crime"], reactions: { likes: 127, dislikes: 26, }, views: 168, userId: 70, }, { id: 8, title: "One can cook on and with an open fire.", body: "One can cook on and with an open fire. These are some of the ways to cook with fire outside. Cooking meat using a spit is a great way to evenly cook meat. In order to keep meat from burning, it's best to slowly rotate it.", tags: ["american", "english"], reactions: { likes: 1271, dislikes: 36, }, views: 2116, userId: 67, }, { id: 9, title: "There are different types of secrets.", body: "There are different types of secrets. She had held onto plenty of them during her life, but this one was different. She found herself holding onto the worst type. It was the type of secret that could gnaw away at your insides if you didn't tell someone about it, but it could end up getting you killed if you did.", tags: ["american", "history", "magical"], reactions: { likes: 703, dislikes: 18, }, views: 2235, userId: 82, }, { id: 10, title: "They rushed out the door.", body: "They rushed out the door, grabbing anything and everything they could think of they might need. There was no time to double-check to make sure they weren't leaving something important behind. Everything was thrown into the car and they sped off. Thirty minutes later they were safe and that was when it dawned on them that they had forgotten the most important thing of all.", tags: ["fiction", "magical", "history"], reactions: { likes: 455, dislikes: 3, }, views: 4504, userId: 144, }, ];
BlogPosts.js
// App.js import "./styles.css"; export default function BlogPosts() { return ( <div> <h2>Blog Posts </h2> </div> ); }
PostCard.js
// PostCard.js //👍 likes | 👎 dislikes | 👁️ views export default function PostCard() { return ( <div> </div> ); }
https://namastedev.com/practice/blog-post
styles.css
body { font-family: sans-serif; background-color: #fafafa; color: #333; } h2 { text-align: center; }
App.js
import "./styles.css"; import BlogPosts from "./BlogPosts.js"; export default function App() { return <BlogPosts />; }
PostsData.js
// postsData.js export default [ { id: 1, title: "His mother had always taught him", body: "His mother had always taught him not to ever think of himself as better than others...", tags: ["history", "american", "crime"], reactions: { likes: 192, dislikes: 25 }, views: 305, userId: 121, }, { id: 2, title: "He was an expert but not in a discipline", body: "He was an expert but not in a discipline that anyone could fully appreciate...", tags: ["french", "fiction", "english"], reactions: { likes: 859, dislikes: 32 }, views: 4884, userId: 91, }, { id: 3, title: "Dave watched as the forest burned up on the hill.", body: "Dave watched as the forest burned up on the hill, only a few miles from her house. The car had been hastily packed and Marta was inside trying to round up the last of the pets. Dave went through his mental list of the most important papers and documents that they couldn't leave behind. He scolded himself for not having prepared these better in advance and hoped that he had remembered everything that was needed. He continued to wait for Marta to appear with the pets, but she still was nowhere to be seen.", tags: ["magical", "history", "french"], reactions: { likes: 1448, dislikes: 39, }, views: 4152, userId: 16, }, { id: 4, title: "All he wanted was a candy bar.", body: "All he wanted was a candy bar. It didn't seem like a difficult request to comprehend, but the clerk remained frozen and didn't seem to want to honor the request. It might have had something to do with the gun pointed at his face.", tags: ["mystery", "english", "american"], reactions: { likes: 359, dislikes: 18, }, views: 4548, userId: 47, }, { id: 5, title: "Hopes and dreams were dashed that day.", body: "Hopes and dreams were dashed that day. It should have been expected, but it still came as a shock. The warning signs had been ignored in favor of the possibility, however remote, that it could actually happen. That possibility had grown from hope to an undeniable belief it must be destiny. That was until it wasn't and the hopes and dreams came crashing down.", tags: ["crime", "mystery", "love"], reactions: { likes: 119, dislikes: 30, }, views: 626, userId: 131, }, { id: 6, title: "Dave wasn't exactly sure how he had ended up", body: "Dave wasn't exactly sure how he had ended up in this predicament. He ran through all the events that had lead to this current situation and it still didn't make sense. He wanted to spend some time to try and make sense of it all, but he had higher priorities at the moment. The first was how to get out of his current situation of being naked in a tree with snow falling all around and no way for him to get down.", tags: ["english", "classic", "american"], reactions: { likes: 15, dislikes: 8, }, views: 38, userId: 98, }, { id: 7, title: "This is important to remember.", body: "This is important to remember. Love isn't like pie. You don't need to divide it among all your friends and loved ones. No matter how much love you give, you can always give more. It doesn't run out, so don't try to hold back giving it as if it may one day run out. Give it freely and as much as you want.", tags: ["magical", "crime"], reactions: { likes: 127, dislikes: 26, }, views: 168, userId: 70, }, { id: 8, title: "One can cook on and with an open fire.", body: "One can cook on and with an open fire. These are some of the ways to cook with fire outside. Cooking meat using a spit is a great way to evenly cook meat. In order to keep meat from burning, it's best to slowly rotate it.", tags: ["american", "english"], reactions: { likes: 1271, dislikes: 36, }, views: 2116, userId: 67, }, { id: 9, title: "There are different types of secrets.", body: "There are different types of secrets. She had held onto plenty of them during her life, but this one was different. She found herself holding onto the worst type. It was the type of secret that could gnaw away at your insides if you didn't tell someone about it, but it could end up getting you killed if you did.", tags: ["american", "history", "magical"], reactions: { likes: 703, dislikes: 18, }, views: 2235, userId: 82, }, { id: 10, title: "They rushed out the door.", body: "They rushed out the door, grabbing anything and everything they could think of they might need. There was no time to double-check to make sure they weren't leaving something important behind. Everything was thrown into the car and they sped off. Thirty minutes later they were safe and that was when it dawned on them that they had forgotten the most important thing of all.", tags: ["fiction", "magical", "history"], reactions: { likes: 455, dislikes: 3, }, views: 4504, userId: 144, }, ];
BlogPosts.js
// BlogPosts.js import React from "react"; import postsData from "./postsData"; import PostCard from "./PostCard"; export default function BlogPosts() { return ( <div style={{ padding: "20px", maxWidth: "800px", margin: "0 auto" }}> <h2>Blog Posts</h2> {postsData.map((post) => ( <PostCard key={post.id} title={post.title} body={post.body} tags={post.tags} reactions={post.reactions} views={post.views} /> ))} </div> ); }
PostCard.js
// PostCard.js //👍 likes | 👎 dislikes | 👁️ views import React from "react"; const PostCard = ({ title, body, tags, reactions, views }) => { return ( <div style={styles.card}> <h3>{title}</h3> <p>{body}</p> <div style={styles.tags}> {tags.map((tag, index) => ( <span key={index} style={styles.tag}> #{tag} </span> ))} </div> <div style={styles.meta}> <span>👍 {reactions.likes}</span> <span>👎 {reactions.dislikes}</span> <span>👁️ {views}</span> </div> </div> ); }; const styles = { card: { border: "1px solid #ccc", padding: "16px", marginBottom: "16px", borderRadius: "8px", backgroundColor: "#ccc9c9", }, meta: { display: "flex", gap: "16px", marginTop: "8px", fontWeight: "bold", }, tags: { marginTop: "10px", }, tag: { marginRight: "8px", color: "blue", padding: "4px 8px", borderRadius: "4px", fontSize: "12px", }, }; export default PostCard;
Holy Grail
Description:
The Holy Grail layout is a classic web page structure that has been a common layout pattern since the early days of web design. It consists of a full-width header at the top, a full-width footer at the bottom, and a three-column content area in the center: a fixed-width left sidebar (commonly used for navigation), a flexible main content area in the center, and a fixed-width right sidebar (often used for ads or additional content).
This layout presents a real-world use case that combines semantic HTML5 elements with modern CSS layout techniques using Flexbox.
In this challenge, you will build a reusable HolyGrailLayout component using React functional components and CSS. The component must follow semantic
HTML5 structure:
* <header> - Appears at the top of the page, typically used for branding or navigation.
* <aside> - Represents side content such as navigation (left) or advertisements (right).
* <main> - Contains the primary content for the page.
* <footer> - Appears at the bottom of the page and typically includes footer links or legal information.
Requirements:
* Component Structure:
A single React component: HolyGrailLayout
Contains the following layout structure:
Header at the top (60px tall)
Footer at the bottom (100px tall)
Three-column body in between:
Left Sidebar (<aside>) - Fixed width: 100px
Center Column (<main>) - Flexible width
Right Sidebar (<aside>) - Fixed width: 100px
* Ul Behavior:
All columns should maintain the same height regardless of content A
The footer should stick to the bottom of the viewport, even if the page has little content The layout must be responsive and maintain proportions when resized
Styling Instructions
* You must use the given classNames “container” and
“columns” given in the default template to apply styling.
Expected Output:
A professional, full-height layout that demonstrates proper use of semantic HTML5 elements with modern CSS. The layout should visually reflect:
* A dark header at the top (60px height)
* A light-colored content section with three columns:
Left column for Navigation (100px wide)
Center column for Main Content (expands to fill space)
Right columisfor Sidebar (100px wide)
* A dark footer at the bottom (100px height) that remains pinned to the bottom of the screen
This should work across various screen sizes and ensure all columns match in height visually.
HolyGrail.jsx
import React from "react"; import "./HolyGrail.css"; export default function HolyGrail() { return ( <div className="container"> <header>Header</header> <div className="columns"> <nav>Navigation</nav> <main>Main</main> <aside>Sidebar</aside> </div> <footer>Footer</footer> </div> ); }
HolyGrail.css
body { font-family: sans-serif; font-size: 12px; font-weight: bold; margin: 0; } * { box-sizing: border-box; } header, nav, main, aside, footer { padding: 12px; } header { background-color: tomato; } nav { background-color: coral; } main { background-color: moccasin; } aside { background-color: sandybrown; } footer { background-color: slategray; }
App.css
import HolyGrail from './HolyGrail.jsx' export default function App() { return <HolyGrail/> }
https://namastedev.com/practice/holy-grail
HolyGrail.jsx
import React from "react"; import "./HolyGrail.css"; export default function HolyGrail() { return ( <div className="container"> <header>Header</header> <div className="columns"> <nav>Navigation</nav> <main>Main</main> <aside>Sidebar</aside> </div> <footer>Footer</footer> </div> ); }
HolyGrail.css
html, body { margin: 0; height: 100%; font-family: sans-serif; font-size: 12px; font-weight: bold; } * { box-sizing: border-box; } /* Overall container should fill full height of the viewport */ .container { display: flex; flex-direction: column; min-height: 100vh; } /* Header and Footer */ header { background-color: tomato; height: 60px; } footer { background-color: slategray; height: 100px; } /* Columns: nav, main, aside */ .columns { display: flex; flex: 1; /* Fill remaining space between header and footer */ } /* Left Sidebar (nav) */ nav { background-color: coral; width: 100px; } /* Center Column */ main { background-color: moccasin; flex: 1; /* Take remaining horizontal space */ } /* Right Sidebar */ aside { background-color: sandybrown; width: 100px; } /* Optional: Padding for each section */ header, nav, main, aside, footer { padding: 12px; }
App.css
import HolyGrail from './HolyGrail.jsx' export default function App() { return <HolyGrail/> }
User Profile
Description
Create a class-based React component called UserProfile that displays a user’s name and a button to toggle visibility of their bio.
Requirements
* Use a class component.
* The component should:
Display the user’s name.
Display the user’s image.
* Contains a “Show Bio” / “Hide Bio” button to toggle the bio visibility.
* When the button is clicked for the first time:
The user’s bio is displayed below the button.
The button text changes from “Show Bio” to “Hide Bio”.
* When the button is clicked again:
The bio is hidden.
The button text switches back to “Show Bio”.
Data to use
const user = { name: 'Jane Doe', bio: 'Frontend developer who loves React and coffee ☕️', image: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/dummyUser.jpg' };
styles.css
button { padding: 10px 16px; background-color: #007bff; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; } button:hover { background-color: #0056b3; } .user-profile { max-width: 400px; margin: 50px auto; border: 2px solid #ddd; border-radius: 8px; background-color: #f9f9f9; text-align: center; padding: 20px; font-family: Arial, sans-serif; } .profile-img { width: 120px; height: 120px; object-fit: cover; border-radius: 50%; margin-bottom: 15px; box-shadow: 0 0 8px rgba(0, 0, 0, 0.1); }
UserProfile.js
import React, { Component } from 'react'; import './styles.css'; const user = { name: 'Jane Doe', bio: 'Frontend developer who loves React and coffee ☕️', image: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/dummyUser.jpg' }; class UserProfile extends Component { render() { return ( <div className="user-profile"> <h2>{user.name}</h2> </div> ); } } export default UserProfile;
App.js
import UserProfile from './UserProfile' export default function App() { return <UserProfile/> }
styles.css
button { padding: 10px 16px; background-color: #007bff; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; } button:hover { background-color: #0056b3; } .user-profile { max-width: 400px; margin: 50px auto; border: 2px solid #ddd; border-radius: 8px; background-color: #f9f9f9; text-align: center; padding: 20px; font-family: Arial, sans-serif; } .profile-img { width: 120px; height: 120px; object-fit: cover; border-radius: 50%; margin-bottom: 15px; box-shadow: 0 0 8px rgba(0, 0, 0, 0.1); }
UserProfile.js
import React, { Component } from 'react'; import './styles.css'; const user = { name: 'Jane Doe', bio: 'Frontend developer who loves React and coffee ☕️', image: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/dummyUser.jpg' }; class UserProfile extends Component { constructor(props) { super(props); this.state = { showBio: false }; } toggleBio = () => { this.setState((prevState) => ({ showBio: !prevState.showBio })); }; render() { const { showBio } = this.state; return ( <div className="user-profile"> <img src={user.image} alt={user.name} className="profile-img" /> <h2>{user.name}</h2> <button onClick={this.toggleBio}> {showBio ? 'Hide Bio' : 'Show Bio'} </button> {showBio && <p>{user.bio}</p>} </div> ); } } export default UserProfile;
App.js
import UserProfile from './UserProfile' export default function App() { return <UserProfile/> }
Contact Form
Create a Contact Form Component that allows users to enter their name, email, and a message, and submit the form. Display a confirmation message after a successful submission.
Requirements
1. The form must contain three fields: name, email, and message and must have labels “Name :”, “Email :”, “Message:”.
2. All fields are required.
3. The email field must be validated to ensure proper format.
4. On submission, show a “Thank you, User” message, where User is the entered name.
5. If you try to submit the form with any of the fields empty, it will prevent submission and show an error message like:
* “Name is required” for the name field.
* “Email is required” for the email field.
* “Message is required” for the message field.
6. If the email is not in valid format show an error message, “Invalid emall format”,
Constraints & Edge Cases
* Constraint 1: Name, email, and message are mandatory fields.
* Constraint 2: Email must be in valid format.
* Edge Case 1: User submits without filling fields → show error.
* Edge Case 2: User enters invalid email → show specific email error.
* Edge Case 3: After successful submission, fields should reset.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
ContactForm.js
import React from "react"; import './styles.css' function ContactForm() { return ( <div> {/* Implement contact form logic here */} </div> ); } export default ContactForm;
App.js
import ContactForm from "./ContactForm"; export default function App() { return <ContactForm />; }
https://namastedev.com/practice/contact-form
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
ContactForm.js
import React, { useState } from "react"; import './styles.css'; function ContactForm() { const [formData, setFormData] = useState({ name: '', email: '', message: '' }); const [errors, setErrors] = useState({}); const [submitted, setSubmitted] = useState(false); const validate = () => { const newErrors = {}; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!formData.name.trim()) { newErrors.name = 'Name is required'; } if (!formData.email.trim()) { newErrors.email = 'Email is required'; } else if (!emailRegex.test(formData.email)) { newErrors.email = 'Invalid email format'; } if (!formData.message.trim()) { newErrors.message = 'Message is required'; } return newErrors; }; const handleChange = (e) => { setFormData({ ...formData, [e.target.name]: e.target.value }); // Clear errors while typing setErrors({ ...errors, [e.target.name]: '' }); }; const handleSubmit = (e) => { e.preventDefault(); const validationErrors = validate(); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); setSubmitted(false); } else { setSubmitted(true); // Clear form after submission setFormData({ name: '', email: '', message: '' }); setErrors({}); } }; return ( <div style={{ maxWidth: '500px', margin: '50px auto' }}> <h1>Contact Us</h1> {submitted && ( <p style={{ color: 'green', fontWeight: 'bold' }}> Thank you, {formData.name || 'User'}! </p> )} <form onSubmit={handleSubmit} noValidate> <div style={{ marginBottom: '15px' }}> <label>Name :</label><br /> <input type="text" name="name" value={formData.name} onChange={handleChange} style={{ width: '100%', padding: '8px' }} /> {errors.name && <p style={{ color: 'red' }}>{errors.name}</p>} </div> <div style={{ marginBottom: '15px' }}> <label>Email :</label><br /> <input type="text" name="email" value={formData.email} onChange={handleChange} style={{ width: '100%', padding: '8px' }} /> {errors.email && <p style={{ color: 'red' }}>{errors.email}</p>} </div> <div style={{ marginBottom: '15px' }}> <label>Message:</label><br /> <textarea name="message" value={formData.message} onChange={handleChange} rows="4" style={{ width: '100%', padding: '8px' }} /> {errors.message && <p style={{ color: 'red' }}>{errors.message}</p>} </div> <button type="submit" style={{ padding: '10px 16px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }}> Submit </button> </form> </div> ); } export default ContactForm;
App.js
import ContactForm from "./ContactForm"; export default function App() { return <ContactForm />; }
Password Strength
Description
Build a password strength checker in React that evaluates and displays the strength level of a user’s password. The goal of this problem is to create a password strength checker that evaluates the strength of a given password based on specific criteria. The password is considered strong if it meets all or 4 of the following rules:
1. Length: At least & characters.
2. Uppercase Letters: At least one uppercase letter (A-Z).
3. Lowercase Letters: At least one lowercase letter (a-z).
4. Numbers: At least one digit (0-9).
5. Special Characters: At least one special character (e.g., @, #, $,%, etc.).
Strength Levels:
* Level 1: Password meets only 1 of the 5 criteria
* Level 2: Password meets 2 or 3 of the 5 criteria
* Level 3: Password meets 4 or 5 of the 5 criteria
* If the password does not meet any criteria, it’s considered a weak password and the function returns “ Weak Password “.
Important Instructions
* Define a helper function called
checkPasswordStrength inside the same file.
* Export that helper function so it can be tested separately
* The function checkPasswordStrength receives a password string as an argument.
* The function checkPasswordStrength and returns Level
1, Level 2, Level 3 or Weak Password based on the criteria.
* The Ul should have:
An input field for password A button to check strength
A strength result displayed after clicking
Example Inputs & Outputs
Example 1:
* Input: “’
* Output: “Weak Password”
* Explanation: The password is empty, so it doesn’t meet any criteria.
Example 2:
* Input: “abc123”
* Output: “Level 1”
* Explanation: The password contains lowercase letters and numbers but doesn’t meet the other criteria (uppercase, special character).
Example 3:
* Input: “abc123ABC”
* Output: “Level 2”
* Explanation: The password meets 3 criteria: length (>=8), lowercase, and numbers, but lacks a special character.
Example 4:
* Input: “Abc12345”
* Output: “Level 2”
* Explanation: The password meets 4 criteria: length, uppercase, lowercase, and numbers, but lacks a special character.
Example 5:
* Input: “Abc@1234”
* Output: “Level 3”
* Explanation: The password meets all 5 criteria: length (=8), uppercase, lowercase, numbers, and special character.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
PasswordStrength.jsx
import React, { useState } from 'react'; import './styles.css' // ✅ Export this so it can be tested export const checkPasswordStrength = () => { }; const PasswordStrength = () => { return ( <div> <h2>Password Strength Checker</h2> </div> ); }; export default PasswordStrength;
App.js
import PasswordStrength from './PasswordStrength' export default function App() { return <PasswordStrength/> }
https://namastedev.com/practice/password-strength
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
PasswordStrength.jsx
import React, { useState } from 'react'; import './styles.css'; // ✅ Exported for testing export const checkPasswordStrength = (password) => { let score = 0; const lengthCheck = password.length >= 8; const upperCheck = /[A-Z]/.test(password); const lowerCheck = /[a-z]/.test(password); const numberCheck = /[0-9]/.test(password); const specialCharCheck = /[!@#$%^&*(),.?":{}|<>]/.test(password); if (lengthCheck) score++; if (upperCheck) score++; if (lowerCheck) score++; if (numberCheck) score++; if (specialCharCheck) score++; if (score === 0) return "Weak Password"; else if (score === 1) return "Level 1"; else if (score === 2 || score === 3) return "Level 2"; else return "Level 3"; }; const PasswordStrength = () => { const [password, setPassword] = useState(''); const [strength, setStrength] = useState(''); const handleCheck = () => { const result = checkPasswordStrength(password); setStrength(result); }; return ( <div style={{ maxWidth: '400px', margin: '50px auto', textAlign: 'center' }}> <h2>Password Strength Checker</h2> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Enter password" style={{ padding: '10px', width: '100%', marginBottom: '10px', fontSize: '16px' }} /> <br /> <button onClick={handleCheck} style={{ padding: '10px 20px', fontSize: '14px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }} > Check Strength </button> {strength && ( <p style={{ marginTop: '20px', fontWeight: 'bold' }}>{strength}</p> )} </div> ); }; export default PasswordStrength;
App.js
import PasswordStrength from './PasswordStrength' export default function App() { return <PasswordStrength/> }
Toggle Password
Description
Create a react component that allows users to input a password. It should toggle password visibility in a secure and accessible way along with a label indicating the visibility status. It should have live toggling using an eye icon.
Requirements
* The input must:
Securely accept user-entered text.
Have a placeholder: “Enter password”.
Be focusable and editable at all times.
Always show the placeholder text when empty.
* By default:
Password should be hidden (masked).
* Visibility toggle icon:
Uses lucide-react icons.
Shows Eye icon when the password is hidden.
Shows Eyeoff icon when the password is visible.
* On clicking the icon:
Toggle the visibility of the password between masked and unmasked.
Instantly update both:
The icon (Eye → EyeOff).
The label (described below).
* A label must appear below the input field showing:
“Password Hidden” when the password is masked.
“Password Visible” when the password is unmasked.
Data Test IDs (Required for Testing)
* data-testid=”password-input”: The password input field
* data-testid=”toggle-icon”: Element wrapping the eye icon used to toggle password visibility
* data-testid=”visibility-label”: Text label showing whether password is visible or hidden
styles.css
body { margin: 0; font-family: "Poppins", sans-serif; background-color: #f0f0f0; } .container { text-align: center; height: 100vh; width: 100vw; display: flex; flex-direction: column; justify-content: center; align-items: center; } h1 { font-size: 30px; margin-bottom: 20px; color: #000000; } .password-wrapper { position: relative; width: 290px; } input[type="password"], input[type="text"] { width: 100%; padding: 10px 35px 10px 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 6px; outline: none; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); background-color: white; } .icon { position: absolute; right: -30px; top: 50%; transform: translateY(-50%); cursor: pointer; color: #888; } .icon:hover { color: #000; } .visibility-label { display: block; margin-top: 6px; font-size: 13px; color: #888; text-align: left; width: 280px; }
App.js
import TogglePassword from './TogglePassword' export default function App() { return <TogglePassword/> }
TogglePassword.jsx
import React, { useState } from "react"; import { Eye, EyeOff } from "lucide-react"; import "./styles.css"; function TogglePassword() { return ( <div className="container"> <h1 className="title">Toggle Password</h1> <div className="password-wrapper"> <input type="text" id="password" placeholder="Enter password" className="password-input" data-testid="password-input" /> <span className="icon" data-testid="toggle-icon" > <EyeOff size={18} /> </span> </div> <span className="visibility-label" data-testid="visibility-label"> Password Hidden </span> </div> ); } export default TogglePassword;
https://namastedev.com/practice/toggle-password
styles.css
body { margin: 0; font-family: "Poppins", sans-serif; background-color: #f0f0f0; } .container { text-align: center; height: 100vh; width: 100vw; display: flex; flex-direction: column; justify-content: center; align-items: center; } h1 { font-size: 30px; margin-bottom: 20px; color: #000000; } .password-wrapper { position: relative; width: 290px; } input[type="password"], input[type="text"] { width: 100%; padding: 10px 35px 10px 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 6px; outline: none; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); background-color: white; } .icon { position: absolute; right: -30px; top: 50%; transform: translateY(-50%); cursor: pointer; color: #888; } .icon:hover { color: #000; } .visibility-label { display: block; margin-top: 6px; font-size: 13px; color: #888; text-align: left; width: 280px; }
App.js
import TogglePassword from './TogglePassword' export default function App() { return <TogglePassword/> }
TogglePassword.jsx
import React, { useState } from "react"; import { Eye, EyeOff } from "lucide-react"; import "./styles.css"; function TogglePassword() { const [visible, setVisible] = useState(false); const [password, setPassword] = useState(""); const toggleVisibility = () => { setVisible((prev) => !prev); }; return ( <div className="container"> <h1 className="title">Toggle Password</h1> <div className="password-wrapper"> <input type={visible ? "text" : "password"} placeholder="Enter password" value={password} onChange={(e) => setPassword(e.target.value)} data-testid="password-input" /> <span className="icon" onClick={toggleVisibility} data-testid="toggle-icon" > {visible ? <EyeOff size={18} /> : <Eye size={18} />} </span> </div> <span className="visibility-label" data-testid="visibility-label"> {visible ? "Password Visible" : "Password Hidden"} </span> </div> ); } export default TogglePassword;
Age Calculator
Description
Create a responsive Age Calculator component that calculates a user’s age in years, months, and days based on a selected or entered birthdate.
Requirements
* A label “Enter/Select a birthdate” indicating the user to either input manually or select a date from the datepicker.
* The interface must include:
An input field with the placeholder of the format (dd-mm-yyyy or mm-dd-yyyy)
The input should use the browser’s built-in datepicker to allow users to manually select day, month, and year.
A button “Calculate Age”
* A display area below the button which will show the results or the errors
* Behavior on clicking the Calculate Age button:
If valid:
Display the result in the format:
“X years, Y months, Z days”
If invalid:
Display an error message:
For future dates- “Birthdate cannot be in the future”
For empty input- “Please select a date”
Edge Cases & Constraints
* Input must be a valid past date
* Empty or future dates must show a user-friendly error
* The datepicker must open when clicked
* Age should be calculated using precise difference in years, months, and days
* The calculation must be accurate even across leap years
* Result must update immediately upon clicking
“Calculate”
Testing Requirements
Data Test IDs (Required for Testing):
* data-testid=”input-birthdate” - Date input field
* data-testid=”btn-calculate” - Calculate age button
* data-testid=”age-result” - Display area for result
* data-testid=”error-msg” - Display area for errors
* datatestid=”label-birthdate” -Label associated with the birthdate input
styles.css
.conatiner { max-width: 380px; margin: 3rem auto; padding: 2rem 2.5rem; background: #d6e8fa; border-radius: 12px; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; color: #222; text-align: center; } .title { font-weight: 700; font-size: 1.9rem; color: #2c3e50; margin-bottom: 1.5rem; letter-spacing: 1.1px; } .label { display: block; text-align: left; font-weight: 600; font-size: 1rem; color: #34495e; margin-bottom: 0.6rem; letter-spacing: 0.7px; } .input-date { width: 90%; padding: 0.6rem 1rem; font-size: 1rem; border: 1.8px solid #bdc3c7; border-radius: 8px; box-shadow: inset 1px 1px 4px rgba(0, 0, 0, 0.05); color: #2c3e50; outline: none; margin-bottom: 1.5rem; font-weight: 500; } .btn-calc { width: 80%; padding: 0.75rem 1rem; font-size: 1.1rem; font-weight: 700; color: #ffffff; background-color: #34495e; border: none; border-radius: 10px; box-shadow: 0 4px 12px rgba(52, 73, 94, 0.5); cursor: pointer; user-select: none; } .error-msg { margin-top: 1.4rem; color: #e74c3c; font-weight: 600; font-size: 0.95rem; letter-spacing: 0.6px; } .age-result { margin-top: 1.4rem; font-weight: 600; font-size: 1.15rem; color: #27ae60; letter-spacing: 0.8px; }
AgeCalculator.js
import React from "react"; function AgeCalculator() { return ( <div className="conatiner"> <h2 className="title"></h2> <label className="label"></label> <input id="birthdate" type="date" className="input-date" /> <button className="btn-calc">Calculate Age</button> <p className="error-msg"></p> <p className="age-result"></p> </div> ); } export default AgeCalculator;
App.js
import AgeCalculator from './AgeCalculator.js' export default function App() { return <AgeCalculator/> }
https://namastedev.com/practice/age-calculator
styles.css
.conatiner { max-width: 380px; margin: 3rem auto; padding: 2rem 2.5rem; background: #d6e8fa; border-radius: 12px; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; color: #222; text-align: center; } .title { font-weight: 700; font-size: 1.9rem; color: #2c3e50; margin-bottom: 1.5rem; letter-spacing: 1.1px; } .label { display: block; text-align: left; font-weight: 600; font-size: 1rem; color: #34495e; margin-bottom: 0.6rem; letter-spacing: 0.7px; } .input-date { width: 90%; padding: 0.6rem 1rem; font-size: 1rem; border: 1.8px solid #bdc3c7; border-radius: 8px; box-shadow: inset 1px 1px 4px rgba(0, 0, 0, 0.05); color: #2c3e50; outline: none; margin-bottom: 1.5rem; font-weight: 500; } .btn-calc { width: 80%; padding: 0.75rem 1rem; font-size: 1.1rem; font-weight: 700; color: #ffffff; background-color: #34495e; border: none; border-radius: 10px; box-shadow: 0 4px 12px rgba(52, 73, 94, 0.5); cursor: pointer; user-select: none; } .error-msg { margin-top: 1.4rem; color: #e74c3c; font-weight: 600; font-size: 0.95rem; letter-spacing: 0.6px; } .age-result { margin-top: 1.4rem; font-weight: 600; font-size: 1.15rem; color: #27ae60; letter-spacing: 0.8px; }
AgeCalculator.js
import React, { useState } from "react"; import "./styles.css"; function AgeCalculator() { const [birthdate, setBirthdate] = useState(""); const [error, setError] = useState(""); const [result, setResult] = useState(""); const calculateAge = () => { setError(""); setResult(""); if (!birthdate) { setError("Please select a date"); return; } const birth = new Date(birthdate); const today = new Date(); if (birth > today) { setError("Birthdate cannot be in the future"); return; } let years = today.getFullYear() - birth.getFullYear(); let months = today.getMonth() - birth.getMonth(); let days = today.getDate() - birth.getDate(); if (days < 0) { months--; const prevMonth = new Date(today.getFullYear(), today.getMonth(), 0); days += prevMonth.getDate(); } if (months < 0) { years--; months += 12; } setResult(`${years} years, ${months} months, ${days} days`); }; return ( <div className="conatiner"> <h2 className="title">Age Calculator</h2> <label className="label" htmlFor="birthdate" data-testid="label-birthdate"> Enter/Select a birthdate </label> <input id="birthdate" type="date" className="input-date" data-testid="input-birthdate" value={birthdate} onChange={(e) => setBirthdate(e.target.value)} /> <button className="btn-calc" data-testid="btn-calculate" onClick={calculateAge}> Calculate Age </button> {error && <p className="error-msg" data-testid="error-msg">{error}</p>} {result && <p className="age-result" data-testid="age-result">{result}</p>} </div> ); } export default AgeCalculator;
App.js
import AgeCalculator from './AgeCalculator.js' export default function App() { return <AgeCalculator/> }
Counter using React
Create a React counter with increment, decrement, and reset functionalities.
The component should have three buttons labeled:
* Increment
* Decrement
* Reset
This React component displays a counter that allows users to:
* Increase the count by 1 when clicking the “Increment” button.
* Decrease the count by 1 when clicking the “Decrement” button.
* Reset the count to zero when clicking the “Reset” button.
* Show the current counter value with the text “Counter”.
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
Counter.js
// Counter.js import React, { useReducer } from 'react'; // Reducer function to handle state transitions based on action type const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; case 'reset': return { count: 0 }; default: return state; } }; const Counter = () => { const [state, dispatch] = useReducer(reducer, { count: 0 }); return ( <div> <h2>Counter: {state.count}</h2> <button onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> <button onClick={() => dispatch({ type: 'reset' })}>Reset</button> </div> ); }; export default Counter;
https://namastedev.com/practice/counter-using-react
styles.css
body { font-family: sans-serif; -webkit-font-smoothing: auto; -moz-font-smoothing: auto; -moz-osx-font-smoothing: grayscale; font-smoothing: auto; text-rendering: optimizeLegibility; font-smooth: always; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } h1 { font-size: 1.5rem; }
Counter.js
// Counter.js import React, { useReducer } from 'react'; import './styles.css'; // ensure styles are applied // Reducer function for state transitions const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; case 'reset': return { count: 0 }; default: return state; } }; const Counter = () => { const [state, dispatch] = useReducer(reducer, { count: 0 }); return ( <div style={{ textAlign: 'center', paddingTop: '50px' }}> <h2>Counter: {state.count}</h2> <div> <button style={{margin: "0px 10px"}} onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button style={{margin: "0px 10px"}} onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> <button style={{margin: "0px 10px"}} onClick={() => dispatch({ type: 'reset' })}>Reset</button> </div> </div> ); }; export default Counter;
Navbar
Description
Create a simple React application with a navigation bar and two pages using React Router v6. The app should include:
* A Navbar with links to Home and About pages
* Separate components for Home and About pages
* Proper routing such that clicking a link changes the content shown without refreshing the page
Requirements:
1. Use React Router v6 Use react-router-dom to define and manage your routes.
2. Navbar
Use the NavLink component from react-router-dom.
Should contain two links:
Home → Navigates to /
About → Navigates to / about
3. Home Page (Home. js)
Route: /
Content: Welcome to the Home Page
4. About Page (About. js)
Route: / about
Content: Welcome to the About Page
5. App Component (App. js)
Should use BrowserRouter, Routes, and Route from react-router-dom.
Render Navbar and show Home or About based on the current route.
styles.css
body { margin: 0; font-family: Arial, sans-serif; overflow: hidden; } .navbar { display: flex; justify-content: end; gap: 20px; background-color: #1e1e2f; padding: 15px 30px; } .nav-item { color: white; text-decoration: none; font-weight: 500; } .nav-item.active { border-bottom: 2px solid #00bcd4; } .page-container { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f8ff; /* Light background color */ text-align: center; font-family: Arial, sans-serif; } /* Style for the heading */ .page-container h2 { color: #333; font-size: 25px; font-weight: bold; }
App.js
import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Navbar from './Navbar'; import Home from './Home'; import About from './About'; const App = () => { return ( <Router> <Navbar /> <div className="page-content"> </div> </Router> ); }; export default App;
Navbar.js
import React from 'react'; import { NavLink } from 'react-router-dom'; import './styles.css'; const Navbar = () => { return ( <nav className="navbar"> </nav> ); }; export default Navbar;
Home.js
import React from 'react'; import './styles.css'; const Home = () => { return ( <div className="page-container"> </div> ); }; export default Home;
About.js
import React from 'react'; const About = () => { return ( <div className="page-container"> </div> ); } export default About;
https://namastedev.com/practice/navbar
styles.css
body { margin: 0; font-family: Arial, sans-serif; overflow: hidden; } .navbar { display: flex; justify-content: end; gap: 20px; background-color: #1e1e2f; padding: 15px 30px; } .nav-item { color: white; text-decoration: none; font-weight: 500; } .nav-item.active { border-bottom: 2px solid #00bcd4; } .page-container { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f8ff; text-align: center; font-family: Arial, sans-serif; } .page-container h2 { color: #333; font-size: 25px; font-weight: bold; }
App.js
import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Navbar from './Navbar'; import Home from './Home'; import About from './About'; const App = () => { return ( <Router> <Navbar /> <div className="page-content"> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> </Routes> </div> </Router> ); }; export default App;
Navbar.js
import React from 'react'; import { NavLink } from 'react-router-dom'; import './styles.css'; const Navbar = () => { return ( <nav className="navbar"> <NavLink to="/" className={({ isActive }) => isActive ? "nav-item active" : "nav-item"}> Home </NavLink> <NavLink to="/about" className={({ isActive }) => isActive ? "nav-item active" : "nav-item"}> About </NavLink> </nav> ); }; export default Navbar;
Home.js
import React from 'react'; import './styles.css'; const Home = () => { return ( <div className="page-container"> <h2>Welcome to the Home Page</h2> </div> ); }; export default Home;
About.js
import React from 'react'; import './styles.css'; const About = () => { return ( <div className="page-container"> <h2>Welcome to the About Page</h2> </div> ); }; export default About;