🟧 - Medium Flashcards

Medium level React coding assignments (51 cards)

1
Q

Todo List

Description
Build a Todo List component where users can:
* Add a new todo item.
* Mark a todo as completed.
* Delete a todo item.
* View the list of all todos.

Requirements
* The component should maintain a list of todos in its state.
* A todo has: id, text, and completed (boolean).
* An input box with placeholder “Enter todo” to type a new todo.
* A button labelled “Add” to add a todo.
* Each todo should display its text and a checkbox to toggle completion.
* Each todo should have a delete button labelled “Delete” to delete a todo.
* Completed todos should appear with a strikethrough style.

Constraints & Edge Cases
* Todo text should not be empty.
* Case-insensitive duplicate entries should be allowed.
* Deleting an item should not affect the remaining list.
* All operations should update the Ul immediately.

https://namastedev.com/practice/todo-list

A

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

TodoList.js

import React, { useState } from "react";
import "./styles.css";

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [inputValue, setInputValue] = useState("");

  const handleAdd = () => {
    const trimmed = inputValue.trim();
    if (trimmed === "") return;

    const newTodo = {
      id: Date.now(),
      text: trimmed,
      completed: false,
    };

    setTodos((prevTodos) => [...prevTodos, newTodo]);
    setInputValue("");
  };

  const toggleComplete = (id) => {
    setTodos((prevTodos) =>
      prevTodos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const deleteTodo = (id) => {
    setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
  };

  return (
    <div style={{ padding: "20px", maxWidth: "400px", margin: "0 auto" }}>
      <h1>Todo List</h1>
      <div>
        <input
          type="text"
          placeholder="Enter todo"
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          style={{ padding: "8px", width: "70%", marginRight: "10px" }}
        />
        <button onClick={handleAdd} style={{ padding: "8px 12px" }}>
          Add
        </button>
      </div>

      <ul style={{ listStyle: "none", padding: 0, marginTop: "20px" }}>
        {todos.map((todo) => (
          <li
            key={todo.id}
            style={{
              display: "flex",
              alignItems: "center",
              marginBottom: "10px",
            }}
          >
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleComplete(todo.id)}
              style={{ marginRight: "10px" }}
            />
            <span
              style={{
                textDecoration: todo.completed ? "line-through" : "none",
                flex: 1,
              }}
            >
              {todo.text}
            </span>
            <button onClick={() => deleteTodo(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

App.js

import TodoList from "./TodoList";

export default function App() {
  return <TodoList />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Tabs Component

Description
Implement a Tabs Component that allows users to switch * between different tab content sections. Each tab should be clickable, and clicking on a tab should update the displayed content accordingly.

Requirements
1. The component should accept a list of tabs as props.
2. Each tab should have a title and content.
3. The first tab should be selected by default.
4. Clicking on a tab should update the displayed content.
5. The component should be reusable and scalable.
Constraints
* Constraint 1: The tabs prop is an array of objects, each containing title and content.
* Constraint 2: Handle an empty tabs array gracefully by displaying “No tabs available”.
* Constraint 3: Handle cases where title is missing in a tab by displaying “Tab 1”, “Tab 2”, according to the tab number.
* Constraint 4: Handle cases where content is missing in a tab by displaying “No content available”.

https://namastedev.com/practice/tabs-component

A

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

Tabs.js

import React, { useState } from "react";
import "./styles.css";

function Tabs({ tabs }) {
  const [activeIndex, setActiveIndex] = useState(0);

  if (!tabs || tabs.length === 0) {
    return <p>No tabs available</p>;
  }

  const getTitle = (tab, index) => tab.title || `Tab ${index + 1}`;
  const getContent = (tab) => tab.content || "No content available";

  return (
    <div>
      {/* Tab Titles */}
      <div style={{ display: "flex", marginBottom: "10px" }}>
        {tabs.map((tab, index) => (
          <button
            key={index}
            onClick={() => setActiveIndex(index)}
            style={{
              padding: "10px 20px",
              marginRight: "5px",
              cursor: "pointer",
              border: "1px solid #ccc",
              backgroundColor: index === activeIndex ? "#eee" : "#fff",
              fontWeight: index === activeIndex ? "bold" : "normal",
            }}
          >
            {getTitle(tab, index)}
          </button>
        ))}
      </div>

      {/* Active Tab Content */}
      <div
        style={{
          padding: "15px",
          border: "1px solid #ccc",
          backgroundColor: "#f9f9f9",
        }}
      >
        {getContent(tabs[activeIndex])}
      </div>
    </div>
  );
}

export default Tabs;

App.js

import Tabs from "./Tabs";

export default function App() {
    const tabsData = [
        { title: "Tab 1", content: "This is the content of Tab 1" },
        { title: "Tab 2", content: "This is the content of Tab 2" },
        { title: "Tab 3", content: "This is the content of Tab 3" }
    ];
    
    return <Tabs tabs={tabsData} />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Todo List II

Description
Build a Todo List component with timer functionality where users can:
* Add a new todo item.
* Start/Pause a timer for each todo.
* Reset a timer to zero.
* Delete a todo item.
* View the list of all todos with their timers.

Requirements
* The component should maintain a list of todos in its state.
* A todo has: id, title, time (in seconds), and isRunning (boolean).
* An input box with placeholder “Enter todo” to type a new todo.
* A button labeled “Add” to add a todo.
* Each todo item must be an < li> element with the attribute data-testid=”todo-item”
* Example of a correctly structured todo item:

<li data-testid="todo-item" className="todo-item">
  <span className="todo-text">Example Todo</span>
  <div className="timer">00:00</div>
  <div className="button-group">
    <button className="timer-button start">Start</button>
    <button className="timer-button reset">Reset</button>
    <button className="delete-button">Delete</button>
  </div>
</li>
  • Each todo should display its text and current time in
    MM:SS format.
  • Each todo should have a labeled Start/Pause, Reset, and Delete buttons.
  • The timer should increment every second when running.
  • Multiple timers should be able to run simultaneously.

Constraints & Edge Cases
* Todo text should not be empty.
* Empty todos should not be added to the list.
* Deleting an item should not affect the remaining list or their timers.
* Pausing a timer should stop it from incrementing until resumed.
* Resetting a timer should set it to 00:00 and stop it.
* All operations should update the UI immediately.
* Timers should continue running even when other todos are being manipulated.

Implementation Details
* Use React hooks for state management.
* Implement proper cleanup for timers to prevent memory leaks.
* Format time display in MM:SS format (e.g., “01:45” for 1 minute and 45 seconds).
* Use appropriate styling to distinguish between running and paused timers.

Expected Output
A functional todo list application where:
* Users can add new todos
* Each todo has its own independent timer
* Timers can be started, paused, and reset
* Todos can be deleted
* The Ul updates in real-time as timers increment

https://namastedev.com/practice/todo-list-ii

A
.App {
  font-family: sans-serif;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.container {
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.todo-container {
  width: 100%;
}

h1 {
  color: #333;
  margin-bottom: 10px;
}

h2 {
  color: #444;
  margin-bottom: 20px;
}

.input-container {
  display: flex;
  margin-bottom: 20px;
}

.todo-input {
  flex-grow: 1;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.add-button {
  background-color: #4a90e2;
  color: white;
  border: none;
  padding: 10px 15px;
  margin-left: 10px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}

.add-button:hover {
  background-color: #3a80d2;
}

.todo-list {
  list-style: none;
  padding: 0;
}

.todo-item {
  background-color: white;
  border-radius: 4px;
  padding: 15px;
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.todo-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.todo-title {
  font-weight: bold;
  margin: 0;
  font-size: 18px;
}

.todo-time {
  color: #666;
  font-size: 16px;
  font-weight: bold;
  margin: 0;
  min-width: 60px;
  text-align: right;
}

.todo-actions {
  display: flex;
  gap: 10px;
}

.timer-button,
.reset-button,
.delete-button {
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  transition: background-color 0.2s;
}

.timer-button.start {
  background-color: #4caf50;
  color: white;
}

.timer-button.start:hover {
  background-color: #3d9c40;
}

.timer-button.pause {
  background-color: #ff9800;
  color: white;
}

.timer-button.pause:hover {
  background-color: #e68900;
}

.reset-button {
  background-color: #f44336;
  color: white;
}

.reset-button:hover {
  background-color: #e53935;
}

.delete-button {
  background-color: #757575;
  color: white;
}

.delete-button:hover {
  background-color: #616161;
}

@media (max-width: 600px) {
  .todo-content {
    flex-direction: column;
    align-items: flex-start;
  }

  .todo-time {
    text-align: left;
    margin-top: 5px;
  }

  .todo-actions {
    flex-wrap: wrap;
  }
}

App.js
~~~

import React from “react”;
import TodoWithTimeout from “./TodoWithTimeout”;
import “./styles.css”;

export default function App() {
return (
<div className="App">
<h2>Todo List with Timer</h2>
<p>
Build a todo list where each task has its own timer that can be started,
paused, and reset.
</p>
<div className="container">
<TodoWithTimeout></TodoWithTimeout>
{/* <Template></Template> */}
</div>
</div>
);
}

TodoWithTimeout.js

import React, { useState, useEffect, useRef } from “react”;
import “./styles.css”;

function formatTime(seconds) {
const mins = String(Math.floor(seconds / 60)).padStart(2, “0”);
const secs = String(seconds % 60).padStart(2, “0”);
return ${mins}:${secs};
}

function TodoWithTimeout() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState(“”);

const timers = useRef({}); // Holds timer intervals keyed by todo id

useEffect(() => {
return () => {
// Cleanup intervals on unmount
Object.values(timers.current).forEach(clearInterval);
};
}, []);

const handleAddTodo = () => {
const trimmed = input.trim();
if (!trimmed) return;

const newTodo = {
  id: Date.now(),
  text: trimmed,
  time: 0,
  running: false,
};
setTodos((prev) => [...prev, newTodo]);
setInput("");   };

const toggleTimer = (id) => {
setTodos((prevTodos) =>
prevTodos.map((todo) => {
if (todo.id === id) {
if (todo.running) {
clearInterval(timers.current[id]);
delete timers.current[id];
} else {
timers.current[id] = setInterval(() => {
setTodos((prev) =>
prev.map((t) =>
t.id === id ? { …t, time: t.time + 1 } : t
)
);
}, 1000);
}
return { …todo, running: !todo.running };
}
return todo;
})
);
};

const resetTimer = (id) => {
clearInterval(timers.current[id]);
delete timers.current[id];
setTodos((prev) =>
prev.map((todo) =>
todo.id === id ? { …todo, time: 0, running: false } : todo
)
);
};

const deleteTodo = (id) => {
clearInterval(timers.current[id]);
delete timers.current[id];
setTodos((prev) => prev.filter((todo) => todo.id !== id));
};

return (
<div className="todo-container">
<h2>Todo with Timer</h2>
<div className="input-container">
<input
type=”text”
className=”todo-input”
data-testid=”todo-input”
placeholder=”Enter todo”
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button
className=”add-button”
data-testid=”add-button”
onClick={handleAddTodo}
>
Add
</button>
</div>
<ul className="todo-list">
{todos.map((todo) => (
<li key={todo.id} data-testid=”todo-item” className=”todo-item”>
<div className="todo-content">
<p className="todo-title">{todo.text}</p>
<p className="todo-time">{formatTime(todo.time)}</p>
</div>
<div className="todo-actions">
<button
className={timer-button ${todo.running ? "pause" : "start"}}
onClick={() => toggleTimer(todo.id)}
>
{todo.running ? “Pause” : “Start”}
</button>
<button
className=”reset-button”
onClick={() => resetTimer(todo.id)}
>
Reset
</button>
<button
className=”delete-button”
onClick={() => deleteTodo(todo.id)}
>
Delete
</button>
</div>
</li>
))}
</ul>
</div>
);
}

export default TodoWithTimeout;
~~~

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Image Gallery

Description
You are tasked with creating a dynamic Image Gallery
Application using React. The application should allow users to view, add, and delete images. Each image is represented bỳ a URL. Users can input a URL to add a new image, click an image to view a larger version, and remove any image they wish.

Requirements
Component Structure
* Use React Functional Components to build the application.
* Structure the application with a main ImageGallery component inside an App component.
Ul Behavior
* Display images in a responsive grid layout.
* Users should be able to:
Add a new image by entering a URL and clicking a button.
Delete an image from the gallery.
Click on any image to open it in a larger view.

Expected Output
* A heading: “Image Gallery”.
* An input field with the placeholder text “Enter image
URL” and a button labeled “Add Image” for adding image URLs.
* A responsive grid layout displaying all added images.
* A delete button on each image labelled “Delete” for deleting image.
* A modal-style popup must display a larger version of the image when clicked, and the modal ‹div> must have id=”modal” so it can be consistently and accurately targeted in tests.
* The large image view should close when the user clicks outside the image.

https://namastedev.com/practice/image-gallery

A

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

ImageGallery.jsx

import React, { useState } from 'react';
import './styles.css';

const ImageGallery = () => {
  const [images, setImages] = useState([]);
  const [input, setInput] = useState('');
  const [selectedImage, setSelectedImage] = useState(null);

  const handleAddImage = () => {
    const trimmed = input.trim();
    if (trimmed) {
      setImages((prev) => [...prev, trimmed]);
      setInput('');
    }
  };

  const handleDeleteImage = (index) => {
    setImages((prev) => prev.filter((_, i) => i !== index));
  };

  const handleClickOutside = (e) => {
    if (e.target.id === 'modal') {
      setSelectedImage(null);
    }
  };

  return (
    <div>
      <h1>Image Gallery</h1>
      {/* Input */}
      <div style={{ marginBottom: '20px' }}>
        <input
          type="text"
          placeholder="Enter image URL"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          style={{ padding: '10px', width: '300px', marginRight: '10px' }}
        />
        <button onClick={handleAddImage}>Add Image</button>
      </div>

      {/* Image Grid */}
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))',
          gap: '15px'
        }}
      >
        {images.map((url, index) => (
          <div key={index} style={{ position: 'relative' }}>
            <img
              src={url}
              alt={`Gallery ${index}`}
              style={{
                width: '100%',
                height: '150px',
                objectFit: 'cover',
                cursor: 'pointer',
                borderRadius: '8px'
              }}
              onClick={() => setSelectedImage(url)}
            />
            <button
              onClick={() => handleDeleteImage(index)}
              style={{
                position: 'absolute',
                top: '5px',
                right: '5px',
                backgroundColor: '#ff4d4f',
                color: 'white',
                border: 'none',
                padding: '5px 10px',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              Delete
            </button>
          </div>
        ))}
      </div>

      {/* Modal */}
      {selectedImage && (
        <div
          id="modal"
          onClick={handleClickOutside}
          style={{
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            backgroundColor: 'rgba(0,0,0,0.7)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            zIndex: 999
          }}
        >
          <img
            src={selectedImage}
            alt="Enlarged"
            style={{
              maxWidth: '90%',
              maxHeight: '90%',
              borderRadius: '8px',
              boxShadow: '0 0 10px rgba(255,255,255,0.5)'
            }}
          />
        </div>
      )}
    </div>
  );
};

export default ImageGallery;

App.js

 import ImageGallery from './ImageGallery'
export default function App() {
  return <ImageGallery/>
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Stopwatch

Description
Build a simple stopwatch with Start, Stop, and Reset functionality. The stopwatch should display elapsed time in seconds and update every second while running.

Requirements
* Display a timer starting at 0.
* Include three buttons: Start, Stop, and Reset.
* On clicking Start, the timer should begin incrementing every second.
* Stop should pause the timer.
* Reset should stop the timer and reset it back to 0.
* Ensure the timer doesn’t increment multiple times if
Start is clicked repeatedly.

Constraints & Edge Cases
* Timer should not increment if already running and Start is clicked again.
* After Reset, the timer should show 0 and stop ticking.
* Stop should not reset the time.
* Memory leaks must be avoided when using intervals.

https://namastedev.com/practice/stopwatch

A

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

Stopwatch.js

import React, { useState, useRef, useEffect } from "react";
import "./styles.css";

function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const intervalRef = useRef(null);

  const startTimer = () => {
    if (!isRunning) {
      setIsRunning(true);
      intervalRef.current = setInterval(() => {
        setSeconds(prev => prev + 1);
      }, 1000);
    }
  };

  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
    setIsRunning(false);
  };

  const resetTimer = () => {
    stopTimer();
    setSeconds(0);
  };

  // Cleanup interval on component unmount
  useEffect(() => {
    return () => {
      clearInterval(intervalRef.current);
    };
  }, []);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <h1>Time: {seconds}s</h1>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
      <button onClick={resetTimer}>Reset</button>
    </div>
  );
}

export default Stopwatch;

App.js

import Stopwatch from "./Stopwatch";

export default function App() {
  return <Stopwatch />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Drag and Drop

Description
Create a drag-and-drop fruits organizer using React that allows users to move fruits between “Available Fruits” and
“Dropped Fruits” columns, reorder them, and reset to the initial state.

Requirements
* Render two droppable columns:
Left column: Available Fruits
Right column: Dropped Fruits
* Display a reset button labeled “Reset Lists” to restore the initial state.
* Fruit Items Display:
Each fruit is a draggable item with a unique name.
Initially, all fruits appear in the “Available Fruits” column.
Empty messages display when a column has no items:
“Drop fruits here” for the Dropped column.
“No fruits here” for the Available column.
* Drag & Drop Behavior:
Dragging a fruit from one column to another moves it to the target column.
Dropping a fruit on another fruit within the same column reorders the items.
Dropping in an empty column area appends the fruit at the end.
Visual feedback during drag helps indicate valid drop targets.

Edge Cases & Constraints:
* Reordering within the same column keeps all items intact.
* Dragging to a different column moves the item entirely.
* Reset button:
Clears the dropped fruits.
Restores all original fruits back to the Available column.

Testing Requirements
1. Data Test IDs (required for testing):
* data-testid=”available-column” - Column for available fruits
* data-testid=”dropped-column” - Column for dropped fruits
* data-testid=”item-{id}” - Individual fruit items, e.g., item-1, item-2
* data-testid=”reset-button” - Reset button to reset all items
* data-testid=”available-empty” - Message when available list is empty
* data-testid=”dropped-empty” - Message when dropped list is empty

https://namastedev.com/practice/drag-and-drop

A

styles.css

body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background: #f4f6f8;
  margin: 0;
  padding: 20px;
  color: #2e3a59;
}

.app-wrapper {
  max-width: 900px;
  margin: 0 auto;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 28px;
  border-bottom: 1px solid #d1d9e6;
  padding-bottom: 10px;
}

h1 {
  font-weight: 700;
  font-size: 1.9rem;
  color: #1f2937;
  margin: 0;
}

.reset-btn {
  background-color: #374151;
  color: #f3f4f6;
  border: none;
  padding: 10px 20px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  box-shadow: 0 3px 6px rgb(55 65 81 / 0.3);
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
  user-select: none;
}

.reset-btn:hover {
  background-color: #1f2937;
  box-shadow: 0 6px 12px rgb(31 41 55 / 0.5);
}

.container {
  display: flex;
  justify-content: space-between;
  gap: 24px;
}

.column {
  background: #ffffff;
  padding: 24px 28px;
  width: 48%;
  min-height: 360px;
  border-radius: 12px;
  box-shadow: 0 10px 20px rgb(0 0 0 / 0.07);
  border: 1px solid #cbd5e1;
  transition: border-color 0.3s ease;
}

.column.drop-zone {
  border: 2px dashed #4b5563;
}

.column:hover {
  border-color: #4b5563;
}

h2 {
  margin-top: 0;
  font-weight: 600;
  font-size: 1.5rem;
  color: #181c23;
  border-bottom: 1px solid #e5e7eb;
  padding-bottom: 8px;
}

.item {
  background: #c8e0f9;
  margin: 14px 0;
  padding: 14px 20px;
  border-radius: 10px;
  cursor: grab;
  user-select: none;
  font-size: 1.15rem;
  color: #374151;
  box-shadow: 0 3px 8px rgb(100 116 139 / 0.1);
  transition: background-color 0.25s ease, box-shadow 0.25s ease;
  border: 1px solid transparent;
}

.item:active {
  cursor: grabbing;
  background-color: #e5e7eb;
  box-shadow: 0 8px 16px rgb(100 116 139 / 0.2);
  border-color: #9ca3af;
}

.empty {
  color: #6b7280;
  font-style: italic;
  margin-top: 36px;
  font-size: 1rem;
  text-align: center;
}

App.js

import DragDrop from "./DragDrop";

export default function App() {
  return <DragDrop />;
}

DragDrop.js

import React, { useState } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import "./styles.css";

const initialFruits = [
  { id: "1", name: "Apple" },
  { id: "2", name: "Banana" },
  { id: "3", name: "Cherry" },
  { id: "4", name: "Date" },
  { id: "5", name: "Elderberry" }
];

const DragDrop = () => {
  const [available, setAvailable] = useState(initialFruits);
  const [dropped, setDropped] = useState([]);

  const handleDragEnd = (result) => {
    const { source, destination } = result;

    if (!destination) return;

    const sourceList = source.droppableId === "available" ? available : dropped;
    const destList = destination.droppableId === "available" ? available : dropped;
    const setSourceList = source.droppableId === "available" ? setAvailable : setDropped;
    const setDestList = destination.droppableId === "available" ? setAvailable : setDropped;

    const [movedItem] = sourceList.splice(source.index, 1);

    if (source.droppableId === destination.droppableId) {
      // Reordering within the same column
      const updatedList = Array.from(sourceList);
      updatedList.splice(destination.index, 0, movedItem);
      setSourceList(updatedList);
    } else {
      // Moving to another column
      const updatedSource = Array.from(sourceList);
      const updatedDest = Array.from(destList);
      updatedDest.splice(destination.index, 0, movedItem);
      setSourceList(updatedSource);
      setDestList(updatedDest);
    }
  };

  const handleReset = () => {
    setAvailable(initialFruits);
    setDropped([]);
  };

  return (
    <div className="app-wrapper">
      <header>
        <h1>Drag & Drop Fruits</h1>
        <button
          className="reset-btn"
          onClick={handleReset}
          data-testid="reset-button"
        >
          Reset Lists
        </button>
      </header>

      <DragDropContext onDragEnd={handleDragEnd}>
        <div className="container">
          {/* Available Fruits Column */}
          <Droppable droppableId="available">
            {(provided, snapshot) => (
              <div
                className={`column ${snapshot.isDraggingOver ? "drop-zone" : ""}`}
                ref={provided.innerRef}
                {...provided.droppableProps}
                data-testid="available-column"
              >
                <h2>Available Fruits</h2>
                {available.length === 0 && (
                  <p className="empty" data-testid="available-empty">
                    No fruits here
                  </p>
                )}
                {available.map((fruit, index) => (
                  <Draggable key={fruit.id} draggableId={fruit.id} index={index}>
                    {(provided) => (
                      <div
                        className="item"
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        data-testid={`item-${fruit.id}`}
                      >
                        {fruit.name}
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>

          {/* Dropped Fruits Column */}
          <Droppable droppableId="dropped">
            {(provided, snapshot) => (
              <div
                className={`column ${snapshot.isDraggingOver ? "drop-zone" : ""}`}
                ref={provided.innerRef}
                {...provided.droppableProps}
                data-testid="dropped-column"
              >
                <h2>Dropped Fruits</h2>
                {dropped.length === 0 && (
                  <p className="empty" data-testid="dropped-empty">
                    Drop fruits here
                  </p>
                )}
                {dropped.map((fruit, index) => (
                  <Draggable key={fruit.id} draggableId={fruit.id} index={index}>
                    {(provided) => (
                      <div
                        className="item"
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        data-testid={`item-${fruit.id}`}
                      >
                        {fruit.name}
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        </div>
      </DragDropContext>
    </div>
  );
};

export default DragDrop;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Animated Loading Skeleton

Description
Create a React component named LoadingSkeleton that® simulates loading a user profile card. While loading, show an animated skeleton (grey boxes and lines with a shimmer effect). After 2 seconds, replace it with real profile content: an image, name, and bio.

Requirements
1. Create a LoadingSkeleton component.
2. Show a skeleton Ul (name line, bio line) while loading.
3. Use a shimmer animation for a smooth user experience.
4. After 2 seconds, display:
A user image (placeholder)
User name (e.g., John Doe)
Bio (e.g., Full-stack developer at XYZ company)

https://namastedev.com/practice/animated-loading-skeleton

A

styles.css

.card {
  width: 300px;
  margin: 40px auto;
  padding: 20px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  text-align: center;
  font-family: sans-serif;
}

.skeleton-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.line {
  height: 20px;
  background-color: #e2e2e2;
  border-radius: 4px;
  margin: 10px 0;
}

.name {
  width: 60%;
}

.bio {
  width: 80%;
}

.skeleton {
  position: relative;
  overflow: hidden;
  background-color: #ddd;
}

.skeleton::after {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
  animation: shimmer 1.5s infinite;
}

.image-skeleton {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin-bottom: 20px;
}

@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

.profile-img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin-bottom: 20px;
}

LoadingSkeleton.js

import React, { useState, useEffect } from "react";
import "./styles.css";

function LoadingSkeleton() {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => setLoading(false), 2000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="card">
      {loading ? (
        <div className="skeleton-wrapper">
          <div className="skeleton image-skeleton"></div>
          <div className="skeleton line name"></div>
          <div className="skeleton line bio"></div>
        </div>
      ) : (
        <div className="content">
          <img
            src="https://via.placeholder.com/150"
            alt="John Doe"
            className="profile-img"
          />
          <h2>John Doe</h2>
          <p>Full-stack developer at XYZ company</p>
        </div>
      )}
    </div>
  );
}

export default LoadingSkeleton;

App.js

import LoadingSkeleton from "./LoadingSkeleton";

export default function App() {
  return <LoadingSkeleton />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Transfer List

Description
Build a simple Transfer List component in React that allows users to move items between two lists: “Available Items” and
“Selected Items”.

Requirements
* Display two lists: Available Items and Selected Items.
* Each item should be represented by a checkbox.
* Provide buttons to move selected items between the lists.
* Only use these items “Item A”, “Item B”, “Item C”
* Handle selection/deselection of items.
* Lists should update accordingly after every move.

Constraints & Edge Cases
* Items must not duplicate when moved.
* Moving an item should remove it from its current list.
* Handle empty selection without error.
* Initial state can be hardcoded for simplicity.

https://namastedev.com/practice/transfer-list

A

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

TransferList.js

import React, { useState } from "react";
import "./styles.css";

export default function TransferList() {
  const initialItems = ["Item A", "Item B", "Item C"];
  const [available, setAvailable] = useState(initialItems);
  const [selected, setSelected] = useState([]);

  const [checkedAvailable, setCheckedAvailable] = useState([]);
  const [checkedSelected, setCheckedSelected] = useState([]);

  const handleCheck = (item, list, setter) => {
    setter((prev) =>
      prev.includes(item)
        ? prev.filter((i) => i !== item)
        : [...prev, item]
    );
  };

  const moveToSelected = () => {
    const newAvailable = available.filter((item) => !checkedAvailable.includes(item));
    const newSelected = [...selected, ...checkedAvailable];
    setAvailable(newAvailable);
    setSelected(newSelected);
    setCheckedAvailable([]);
  };

  const moveToAvailable = () => {
    const newSelected = selected.filter((item) => !checkedSelected.includes(item));
    const newAvailable = [...available, ...checkedSelected];
    setSelected(newSelected);
    setAvailable(newAvailable);
    setCheckedSelected([]);
  };

  return (
    <div style={{ display: "flex", justifyContent: "center", gap: "50px", paddingTop: "30px" }}>
      <div>
        <h1>Available Items</h1>
        {available.length === 0 ? <p>No items</p> : null}
        {available.map((item) => (
          <div key={item}>
            <label>
              <input
                type="checkbox"
                checked={checkedAvailable.includes(item)}
                onChange={() => handleCheck(item, available, setCheckedAvailable)}
              />
              {item}
            </label>
          </div>
        ))}
        <button onClick={moveToSelected} disabled={checkedAvailable.length === 0}>
          Move to Selected →
        </button>
      </div>

      <div>
        <h1>Selected Items</h1>
        {selected.length === 0 ? <p>No items</p> : null}
        {selected.map((item) => (
          <div key={item}>
            <label>
              <input
                type="checkbox"
                checked={checkedSelected.includes(item)}
                onChange={() => handleCheck(item, selected, setCheckedSelected)}
              />
              {item}
            </label>
          </div>
        ))}
        <button onClick={moveToAvailable} disabled={checkedSelected.length === 0}>
          ← Move to Available
        </button>
      </div>
    </div>
  );
}

App.js

import TransferList from "./TransferList";

export default function App() {
  return <TransferList />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Modal In React

Description
Create a simple, functional modal popup in React with clear open/close behavior. This component demonstrates Ul state management with useState, conditional rendering, and handling user interactions such as clicking outside the modal or on the close button.

Component Details
You need to implement a Modal component that:
1. Displays a button labeled “Open Modal”.
2. Opens the modal when the “Open Modal” button is
* clicked.
3. Displays modal content with the following:
A heading: “Modal Header”
A paragraph: “This is the modal body”
A “Close” button inside the modal
4. Closes the modal when:
The “Close” button is clicked
The user clicks outside the modal (on the backdrop)
5. Does not close the modal when clicking inside the modal content
6. The outermost div that wraps the modal (when visible) must have data-testid=”modal-backdrop” for testing.

https://namastedev.com/practice/modal-in-react

A

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

Modal.js

import React, { useState } from "react";

function Modal() {
  const [isOpen, setIsOpen] = useState(false);

  const handleOpen = () => setIsOpen(true);
  const handleClose = () => setIsOpen(false);

  const handleBackdropClick = (e) => {
    // Only close if the user clicks directly on the backdrop
    if (e.target.dataset.testid === "modal-backdrop") {
      handleClose();
    }
  };

  return (
    <div style={{ textAlign: "center", padding: "50px", height: "100vh" }}>
      <h1>Modal Popup</h1>

      <button
        style={{ padding: "10px", cursor: "pointer" }}
        onClick={handleOpen}
      >
        Open Modal
      </button>

      {isOpen && (
        <div
          data-testid="modal-backdrop"
          onClick={handleBackdropClick}
          style={{
            position: "fixed",
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            backgroundColor: "rgba(0, 0, 0, 0.4)",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
            zIndex: 1000,
          }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              background: "white",
              padding: "30px",
              borderRadius: "8px",
              minWidth: "300px",
              boxShadow: "0 4px 12px rgba(0,0,0,0.2)",
              textAlign: "left",
            }}
          >
            <h2>Modal Header</h2>
            <p>This is the modal body</p>
            <button onClick={handleClose} style={{ marginTop: "20px" }}>
              Close
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

export default Modal;

App.js

import React, { useState } from "react";
import Modal from "./Modal"; 
import './styles.css'

export default function App() {
  return (
   <Modal/>
  );
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

List Sorter

Description
The ListSorter component allows users to view and sort a predefined list of fruits by three different criteria: alphabetically A-Z, reverse alphabetically Z-A, and by name length (shortest to longest). The component starts by displaying the fruits in their original, hardcoded order, and only updates when the user chooses a sort option from a dropdown.
To maintain correctness, the original input list must remain consistent across usage and tests - this list is:
["Banana", "Apple", "Cherry", "Mango", "Blueberry”]
This list is used to check the initial state of the component before any sorting is applied. It ensures test reliability and aligns with expected behaviors such as stable sorting and unaltered default rendering. The component leverages React’s useState to manage both the list and the selected sort type, updating the list based on the selected sort criteria while preserving the original list structure through immutability.

Requirements
* Display a list of fruit names.
* Provide a dropdown to select the sort type with three options:
“A - Z (Alphabetical)” - sort the list alphabetically from A to Z.
“Z - A (Reverse Alphabetical) - sort the list alphabetically from Z to A.
“Length (Shortest First)” - sort the list by the length of the fruit names from shortest to longest.
* When the user selects a sort option, the list updates immediately to reflect the sorting order.
* The component should maintain the current sorting state and update the list accordingly.
* The dropdown should use the following values for selection, which must be tested using:
Corresponding dropdown option values:
* A - Z (Alphabetical) - “az”
* Z - A (Reverse Alphabetical) - “za”
* Length (Shortest First) - “length”

Edge Cases & Constraints
* The initial list order should be preserved until the user selects a sort option.
* Sorting should be stable and accurate for all fruit names.
* Sorting by length should order fruits by their string length in ascending order.
* The list should update on every change of the dropdown value.
* The component should handle cases where multiple fruits might have the same length or alphabetical order.

Example Inputs & Outputs

// Initial List
["Banana", "Apple", "Cherry", "Mango", "Blueberry", "Kiwi", "Pineapple", "Fig"]

// After selecting "A - Z (Alphabetical)"
["Apple", "Banana", "Blueberry", "Cherry", "Fig", "Kiwi", "Mango", "Pineapple"]

// After selecting "Z - A (Reverse Alphabetical)"
["Pineapple", "Mango", "Kiwi", "Fig", "Cherry", "Blueberry", "Banana", "Apple"]

// After selecting "Length (Shortest First)"
["Fig", "Kiwi", "Apple", "Mango", "Banana", "Cherry", "Blueberry", "Pineapple"]

Testing Requirements
* Verify that the component renders the heading, dropdown, and all list items correctly.
* Verify that the initial list order is exactly the original list.
* Test sorting for each sort type:
Alphabetical A-Z
Alphabetical Z-A
Length (Shortest First)
* Verify that the dropdown reflects the current selected sort option after user interaction.
Data Test IDs (required for testing)
* data-testid=”container” - main component container div.
* data-testid=”heading” - heading element with the component title.
* data-testid=”sort-dropdown” - select dropdown element for sorting.
* data-testid=”list-item” - each < li> representing a fruit.

https://namastedev.com/practice/list-sorter

A

styles.css

div[data-testid="container"] {
  max-width: 400px;
  margin: 50px auto;
  padding: 36px 32px;
  font-family: "Poppins", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background-color: #ede7f6;
  border-radius: 20px;
  box-shadow: 0 15px 40px rgba(107, 91, 149, 0.25);
  color: #4b3b72;
  user-select: none;
}

h2[data-testid="heading"] {
  font-size: 2.25rem;
  margin-bottom: 32px;
  font-weight: 700;
  color: #6b5b95;
  text-align: center;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(155, 89, 182, 0.2);
}

label[for="sort"] {
  display: block;
  margin-bottom: 16px;
  font-weight: 600;
  font-size: 1.1rem;
  color: #6b5b95;
}

select[data-testid="sort-dropdown"] {
  width: 100%;
  padding: 14px 18px;
  font-size: 1.1rem;
  border-radius: 14px;
  border: 2px solid #b8a9c9;
  background-color: #ffffff;
  color: #4b3b72;
  cursor: pointer;
  transition: border-color 0.35s ease, box-shadow 0.35s ease;
  box-shadow: inset 0 3px 8px rgba(184, 169, 201, 0.3);
  font-weight: 600;
}

select[data-testid="sort-dropdown"]:focus {
  border-color: #9b59b6;
  box-shadow: 0 0 14px rgba(155, 89, 182, 0.6);
  outline: none;
}

ul[data-testid="list"] {
  list-style: none;
  padding-left: 0;
  margin-top: 36px;
  border-radius: 18px;
  background-color: #ffffff;
  box-shadow: 0 12px 40px rgba(107, 91, 149, 0.15);
  border: 1.8px solid #b8a9c9;
  user-select: text;
}

li[data-testid="list-item"] {
  padding: 18px 28px;
  border-bottom: 1.4px solid #b8a9c9;
  font-size: 1.2rem;
  color: #4b3b72;
  font-weight: 600;
  transition: background-color 0.3s ease, color 0.3s ease;
  cursor: default;
}

li[data-testid="list-item"]:hover {
  background-color: #59a2b6;
  color: #ede7f6;
  font-weight: 700;
  transform: scale(1.03);
  box-shadow: 0 6px 14px rgba(155, 89, 182, 0.4);
}

li[data-testid="list-item"]:last-child {
  border-bottom: none;
}

App.js

import React from "react";
import ListSorter from "./ListSorter";
import "./styles.css";

// Default list passed as prop
const defaultFruits = [
  "Banana",
  "Apple",
  "Cherry",
  "Mango",
  "Blueberry",
  "Kiwi",
  "Pineapple",
  "Fig",
];

export default function App() {
  return <ListSorter initialList={defaultFruits} />;
}

ListSorter.js

import React, { useState } from "react";
import "./styles.css";

export default function ListSorter({ initialList = [] }) {
  const [sortType, setSortType] = useState(""); // No sort by default
  const [displayList, setDisplayList] = useState([...initialList]);

  const handleSortChange = (e) => {
    const value = e.target.value;
    setSortType(value);

    let sorted = [...initialList]; // Always sort from the original list

    if (value === "az") {
      sorted.sort((a, b) => a.localeCompare(b));
    } else if (value === "za") {
      sorted.sort((a, b) => b.localeCompare(a));
    } else if (value === "length") {
      sorted.sort((a, b) => a.length - b.length);
    }

    setDisplayList(sorted);
  };

  return (
    <div data-testid="container">
      <div>
        <h2 data-testid="heading">List Sorter</h2>
      </div>

      <label htmlFor="sort">Sort By:</label>
      <select
        id="sort"
        data-testid="sort-dropdown"
        value={sortType}
        onChange={handleSortChange}
      >
        <option value="">-- Select --</option>
        <option value="az">A - Z (Alphabetical)</option>
        <option value="za">Z - A (Reverse Alphabetical)</option>
        <option value="length">Length (Shortest First)</option>
      </select>

      <ul data-testid="list">
        {displayList.map((fruit, index) => (
          <li key={index} data-testid="list-item">
            {fruit}
          </li>
        ))}
      </ul>
    </div>
  );
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Multiselect Dropdown

Description
Create a React component that allows users to select multiple options with checkboxes from a dropdown menu. The component must handle option selection, deselection, and allow resetting all selections. It should display the current selection count and the selected options and validate user input on submission.

Requirements
Functional Requirements
* The component must:
Display a label above the dropdown with the text
“Select Options:”.
Show a dropdown toggle button with placeholder text
“Choose Options” when no option is selected.
Show the count of selected options (e.g., “3 selected”’) when options are selected.
Include a dropdown icon that rotates on toggle open/close. Use lucide-icon “ChevronDown” Display exactly 10 options (eg. “Option 2, Option 7” ) with checkboxes inside the dropdown menu. The menu should be scrollable. It should be in a list format (<li></li>)
Allow selecting or deselecting multiple options by clicking each option.
Provide a “Reset Selection” button on top inside the dropdown menu to clear all selections.
Close the dropdown menu when clicking outside the component.
Show a submit button below the dropdown. The button is clicked after the menu is closed.
On submit:
If no option is selected, display an error message:
“Please select at least one option.”
If options are selected, display the selected options below the submit button: “Selected: Option 3, Option 5”

Edge cases and constraints
* Submitting with valid selections should not show any error.
* Clicking an option multiple times should toggle selection (select/deselect).
* Leading/trailing spaces in option labels (if any) must not affect selection logic.
* Dropdown button should display “Choose Options” if no options are selected.
* After valid submission, selected options should be clearly displayed in the result area.
* Clicking the Reset button must:
Clear all selected options
, Hide any error messages
Clear previous results
* Dropdown icon must rotate only when the menu is open.

Testing Requirements
Data Test IDs (Required for Testing)
* data-testid=”label”: Label text element.
* data-testid=”dropdown-button”: The dropdown toggle button.
* data-testid=”dropdown-icon”: Icon element indicating dropdown toggle state.
* data-testid=”dropdown-menu”: The container element for the dropdown options.
* data-testid={option-${option}}: Each option item container, e.g., option-Option 1.
* data-testid=”reset-button”: The Reset selections button.
* data-testid=”submit-button”: Submit button element.
* data-testid=”error-message”: Element showing validation error messages.
* data-testid=”selected-options”: Element
showing the list of selected options.
* classname= “rotate”: Used to check the rotation of the icon.

https://namastedev.com/practice/multiselect-dropdown

A

App.js

import MultiSelectDropdown from "./MultiSelectDropdown";

export default function App() {
  return <MultiSelectDropdown />;
}

MultiSelectDropdown.js

import React, { useState, useRef, useEffect } from "react";
import { ChevronDown } from "lucide-react";
import "./styles.css";

const OPTIONS = Array.from({ length: 10 }, (_, i) => `Option ${i + 1}`);

function MultiSelectDropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState([]);
  const [error, setError] = useState("");
  const [submittedOptions, setSubmittedOptions] = useState([]);
  const dropdownRef = useRef(null);

  const toggleDropdown = () => {
    setIsOpen((prev) => !prev);
  };

  const handleOptionToggle = (option) => {
    setSelected((prev) =>
      prev.includes(option)
        ? prev.filter((item) => item !== option)
        : [...prev, option]
    );
    setError("");
    setSubmittedOptions([]);
  };

  const handleReset = () => {
    setSelected([]);
    setError("");
    setSubmittedOptions([]);
  };

  const handleSubmit = () => {
    setIsOpen(false);
    if (selected.length === 0) {
      setError("Please select at least one option.");
      setSubmittedOptions([]);
    } else {
      setError("");
      setSubmittedOptions([...selected]);
    }
  };

  const handleClickOutside = (e) => {
    if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
      setIsOpen(false);
    }
  };

  useEffect(() => {
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  return (
    <div className="dropdown-container" ref={dropdownRef}>
      <h2 className="dropdown-title">Multiselect Dropdown Menu</h2>
      <label data-testid="label" className="dropdown-label">Select Options:</label>

      <div className="dropdown-wrapper">
        <button
          className="dropdown-toggle"
          onClick={toggleDropdown}
          data-testid="dropdown-button"
        >
          <span
            data-testid="dropdown-icon"
            className={`dropdown-icon ${isOpen ? "rotate" : ""}`}
          >
            <ChevronDown />
          </span>
          <span className="dropdown-button-label">
            {selected.length === 0
              ? "Choose Options"
              : `${selected.length} selected`}
          </span>
        </button>

        {isOpen && (
          <ul className="dropdown-menu" data-testid="dropdown-menu">
            <li
              className="dropdown-reset"
              onClick={handleReset}
              data-testid="reset-button"
            >
              Reset Selection
            </li>
            {OPTIONS.map((option) => (
              <li
                key={option}
                className="dropdown-option"
                data-testid={`option-${option}`}
                onClick={() => handleOptionToggle(option)}
              >
                <input
                  type="checkbox"
                  checked={selected.includes(option)}
                  onChange={() => {}}
                />
                <span className="option-label">{option}</span>
              </li>
            ))}
          </ul>
        )}
      </div>

      <button
        className="submit-button"
        onClick={handleSubmit}
        data-testid="submit-button"
      >
        Submit
      </button>

      {error && (
        <div className="error" data-testid="error-message">
          {error}
        </div>
      )}

      {submittedOptions.length > 0 && (
        <div className="result-area" data-testid="selected-options">
          Selected: {submittedOptions.join(", ")}
        </div>
      )}
    </div>
  );
}

export default MultiSelectDropdown;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Progress Bar II

Description
You’re given a task to display a list of progress bars with different percentage values (10%, 20%, .*, 100%), Each progress bar should:
1. Animate to the given percentage after a delay of 1 second.
2. Visually fill the bar based on the percentage using a
CSS transform.
3. Display the numeric progress as text (e.g., “20%”).
4. Show the text color as:
Black if progress is less than 5%.
White otherwise.
5. Have a green background and smooth animation using CSS transitions.
You are provided with two components:
* App. js: Renders a list of ProgressBar components.
* ProgressBar. js: A single progress bar that updates after 1 second using useEffect.

Your Task:
1. The progress bar text updates from 0% to the correct percentage after 100 ms.
2. The visual fill (via transform: translateX(…))
corresponds to the progress value.
3. The background color is green.
4. Text color should be white > 5% else black.
5. The transition style is smooth (transition: 0.5s ease-in).
6. The update happens with a delay of 100ms.
7. It is mandatory for the ProgressBar to have role=”progressbar” so it can be properly identified and tested for accessibility and styling.

https://namastedev.com/practice/progress-bar-ii

A

styles.css

.App {
  font-family: sans-serif;
  text-align: center;
  padding: 20px;
}

.outer {
  width: 80%;
  height: 30px;
  margin: 20px auto;
  border: 1px solid #ccc;
  background-color: #eee;
  border-radius: 6px;
  overflow: hidden;
  position: relative;
}

.inner {
  height: 100%;
  background-color: green;
  display: flex;
  align-items: center;
  justify-content: right;
  transition: transform 0.5s ease-in;
  transform: translateX(-100%);
  white-space: nowrap;
  font-weight: bold;
  font-size: 14px;
}

App.js

import "./styles.css";
import ProgressBar from "./ProgressBar";

export default function App() {
  const bars = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];

  return (
    <div className="App">
      <h1>Progress bar</h1>
      {bars.map((value, index) => (
        <ProgressBar key={index} progress={value} />
      ))}
    </div>
  );
}

ProgressBar.js

import { useEffect, useState } from "react";
import "./styles.css";

const ProgressBar = ({ progress }) => {
  const [currentProgress, setCurrentProgress] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => {
      setCurrentProgress(progress);
    }, 100);
    return () => clearTimeout(timer);
  }, [progress]);

  const transformStyle = {
    transform: `translateX(${currentProgress - 100}%)`,
    color: currentProgress < 5 ? "black" : "white"
  };

  return (
    <div className="outer">
      <div
        className="inner"
        role="progressbar"
        style={transformStyle}
      >
        {currentProgress}%
      </div>
    </div>
  );
};

export default ProgressBar;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Reusable Toast

Description
In this problem, you need to implement a “toast” notification feature that provides brief feedback to users in the form of a popup. The toast should:
* Accept a message (string)
* Accept a type (success, error, or info)
* Accept a duration (milliseconds)
Toasts should:
* Appear at the top or bottom of the screen
* Automatically disappear after the specified time
* Allow multiple toasts to be displayed simultaneously
* Show different styles depending on the type (color-coded: green for success, red for error, blue for info)
Toast Container:
* Show Success - On clicking this button a success toast appears.
* Show Error - On clicking this button an error toast appears.
* Show Info - On clicking this button an info toast appears.

Example Inputs & Outputs

Input: addToast("Data saved successfully!", "success", 3000)
Output: Toast with green background appears for 3 seconds

Input: addToast("Error saving data!", "error", 5000)
Output: Toast with red background appears for 5 seconds

Input: addToast("Information loaded", "info", 4000)
Output: Toast with blue background appears for 4 seconds

Constraints & Edge Cases
* Each toast should auto-dismiss after its specified duration.
* Support showing multiple toasts at once.
* Each toast should be uniquely identifiable for removal.
* The component must support easy customization of message, duration, and type.
* Ensure toasts don’t overlap visually in a confusing way.
* Make sure to use inline css.

https://namastedev.com/practice/reusable-toast

A

Toast.jsx

import React, { useEffect } from 'react';

const Toast = ({ id, message, type, duration, onRemove }) => {
  useEffect(() => {
    const timer = setTimeout(() => onRemove(id), duration);
    return () => clearTimeout(timer);
  }, [id, duration, onRemove]);

  const backgroundColors = {
    success: '#4CAF50',
    error: '#F44336',
    info: '#2196F3',
  };

  const toastStyle = {
    padding: '12px 20px',
    marginBottom: '10px',
    color: 'white',
    borderRadius: '6px',
    backgroundColor: backgroundColors[type] || '#333',
    minWidth: '200px',
    boxShadow: '0 2px 8px rgba(0,0,0,0.2)',
    fontSize: '16px',
  };

  return <div style={toastStyle}>{message}</div>;
};

export default Toast;

ToastContainer.jsx

import React, { useState } from 'react';
import Toast from './Toast';

let toastId = 0;

const ToastContainer = () => {
  const [toasts, setToasts] = useState([]);

  const addToast = (message, type, duration) => {
    const id = toastId++;
    const newToast = { id, message, type, duration };
    setToasts((prev) => [...prev, newToast]);
  };

  const removeToast = (id) => {
    setToasts((prev) => prev.filter((toast) => toast.id !== id));
  };

  const containerStyle = {
    position: 'fixed',
    top: '20px',
    right: '20px',
    zIndex: 1000,
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'flex-end',
  };

  const buttonContainerStyle = {
    display: 'flex',
    gap: '10px',
    marginBottom: '20px',
  };

  const buttonStyle = {
    padding: '10px 16px',
    fontSize: '14px',
    fontWeight: 'bold',
    borderRadius: '6px',
    border: 'none',
    cursor: 'pointer',
    color: 'white',
  };

  return (
    <div>
      <div style={buttonContainerStyle}>
        <button
          style={{ ...buttonStyle, backgroundColor: '#4CAF50' }}
          onClick={() => addToast('Data saved successfully!', 'success', 3000)}
        >
          Show Success
        </button>
        <button
          style={{ ...buttonStyle, backgroundColor: '#F44336' }}
          onClick={() => addToast('Error saving data!', 'error', 5000)}
        >
          Show Error
        </button>
        <button
          style={{ ...buttonStyle, backgroundColor: '#2196F3' }}
          onClick={() => addToast('Information loaded', 'info', 4000)}
        >
          Show Info
        </button>
      </div>

      <div style={containerStyle}>
        {toasts.map((toast) => (
          <Toast key={toast.id} {...toast} onRemove={removeToast} />
        ))}
      </div>
    </div>
  );
};

export default ToastContainer;

App.js

import React from 'react';
import ToastContainer from './ToastContainer';

const App = () => {
  return (
    <div>
      <ToastContainer />
    </div>
  );
};

export default App;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

BMI Calculator

**Description **
Create a BMI (Body Mass Index) Calculator in React. The application should allow users to enter their weight in kilograms and height in centimeters, and on clicking a button, it should compute the BMI and display the corresponding category.

Requirements
Input Fields
* Weight (in kg) with placeholder “Weight (kg)”
* Height (in cm) with placeholder “Height (cm)”
On Clicking a button with label “Calculate BMI”
* Use the formula:
BMI = weight / ((height / 100) ^ 2)
* Round the BMI to 1 decimal place
* Display:
The BMI value - The BMI value with the text: “Your BMI:
X”
The BMI category - The BMI category with the text:
“Category: Y”
Where X is the calculated BMI and Y is the corresponding category (like Normal, Overweight, etc.).

BMI Categories
* Underweight: BMI < 18.5
* Normal: 18.5 ≤ BMI < 24.9
* Overweight: 25 ≤ BMI < 29.9
* Obese: BMI ≥ 30
Additional Feature
* Add a “Reset” button with label Reset to clear both inputs and the result.

Constraints & Edge Cases
* Weight and height must be positive numbers
* Input fields must not be empty before calculation
* Result should be rounded to 1 decimal place
* Reset must clear all fields and result
* BMI result must not be shown before clicking
“Calculate BMI”

https://namastedev.com/practice/bmi-calculator

A

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

BMICalculator.js

import React, { useState } from "react";
import './styles.css';

function BMICalculator() {
  const [weight, setWeight] = useState('');
  const [height, setHeight] = useState('');
  const [bmi, setBMI] = useState(null);
  const [category, setCategory] = useState('');

  const calculateBMI = () => {
    const w = parseFloat(weight);
    const h = parseFloat(height);

    if (!w || !h || w <= 0 || h <= 0) {
      alert("Please enter valid positive numbers for weight and height.");
      return;
    }

    const bmiValue = w / ((h / 100) ** 2);
    const roundedBMI = Math.round(bmiValue * 10) / 10;
    setBMI(roundedBMI);
    setCategory(getCategory(roundedBMI));
  };

  const getCategory = (bmi) => {
    if (bmi < 18.5) return "Underweight";
    else if (bmi < 24.9) return "Normal";
    else if (bmi < 29.9) return "Overweight";
    else return "Obese";
  };

  const reset = () => {
    setWeight('');
    setHeight('');
    setBMI(null);
    setCategory('');
  };

  return (
    <div style={{ padding: '20px', maxWidth: '400px', margin: '0 auto' }}>
      <h2>BMI Calculator</h2>

      <div style={{ marginBottom: '10px' }}>
        <input
          type="number"
          value={weight}
          onChange={(e) => setWeight(e.target.value)}
          placeholder="Weight (kg)"
          style={{ padding: '8px', width: '100%' }}
        />
      </div>

      <div style={{ marginBottom: '10px' }}>
        <input
          type="number"
          value={height}
          onChange={(e) => setHeight(e.target.value)}
          placeholder="Height (cm)"
          style={{ padding: '8px', width: '100%' }}
        />
      </div>

      <div style={{ marginBottom: '10px', display: 'flex', gap: '10px' }}>
        <button onClick={calculateBMI} style={{ padding: '8px 16px' }}>Calculate BMI</button>
        <button onClick={reset} style={{ padding: '8px 16px' }}>Reset</button>
      </div>

      {bmi !== null && (
        <div style={{ marginTop: '15px' }}>
          <p><strong>Your BMI:</strong> {bmi}</p>
          <p><strong>Category:</strong> {category}</p>
        </div>
      )}
    </div>
  );
}

export default BMICalculator;

App.js

import BMICalculator from "./BMICalculator";

export default function App() {
  return <BMICalculator />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Image Carousel

Description
The image carousel component takes in an array of image URLs. Example image URLs are provided in the skeleton code.

Layout and positioning:
* The image carousel should be centered on the screen with a maximum size of 600px by 400px. Images should shrink to fit within the carousel so that the entire image is visible.
* Empty parts of the carousel can be filled with black.
* If the screen width is smaller than the image, the carousel should be resized to fit within the available horizontal space.

Navigation:
* Left and Right Navigation Buttons to allow users to navigate through the images.
The left button (®) must have id=”Previous”.
The right button (E) must have id=”Next”.
* The buttons should allow a cycling behavior, i.e. after the last image, the image cycles back to the first.
* Add page buttons at the bottom to directly jump to an image. You may assume there will be fewer than 10 images.
* Each page button must have a unique id in the format pageButton-<index> (e.g., pageButton-0, pageButton-1).
* A message “No images available.” must be shown when the image array is empty.</index>

https://namastedev.com/practice/image-carousel

A

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

ImageCarousel.jsx

import React, { useState } from "react";
import "./styles.css";

const ImageCarousel = ({ images = [] }) => {
  const [currentIndex, setCurrentIndex] = useState(0);

  const hasImages = images.length > 0;

  const goToPrevious = () => {
    setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1));
  };

  const goToNext = () => {
    setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
  };

  const goToPage = (index) => {
    setCurrentIndex(index);
  };

  if (!hasImages) {
    return (
      <div style={{ textAlign: "center", marginTop: "20px" }}>
        No images available.
      </div>
    );
  }

  return (
    <div
      style={{
        maxWidth: "600px",
        width: "100%",
        margin: "0 auto",
        textAlign: "center",
        position: "relative",
      }}
    >
      <div
        style={{
          backgroundColor: "black",
          height: "400px",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <img
          src={images[currentIndex].src}
          alt={images[currentIndex].alt}
          style={{
            maxWidth: "100%",
            maxHeight: "100%",
            objectFit: "contain",
          }}
        />
      </div>

      {/* Navigation Arrows */}
      <button
        id="Previous"
        onClick={goToPrevious}
        style={{
          position: "absolute",
          top: "50%",
          left: "10px",
          transform: "translateY(-50%)",
          fontSize: "24px",
          background: "rgba(255,255,255,0.7)",
          border: "none",
          cursor: "pointer",
          padding: "8px",
        }}
      >
        ◀
      </button>

      <button
        id="Next"
        onClick={goToNext}
        style={{
          position: "absolute",
          top: "50%",
          right: "10px",
          transform: "translateY(-50%)",
          fontSize: "24px",
          background: "rgba(255,255,255,0.7)",
          border: "none",
          cursor: "pointer",
          padding: "8px",
        }}
      >
        ▶
      </button>

      {/* Pagination Buttons */}
      <div style={{ marginTop: "10px" }}>
        {images.map((_, index) => (
          <button
            key={index}
            id={`pageButton-${index}`}
            onClick={() => goToPage(index)}
            style={{
              margin: "0 4px",
              padding: "5px 10px",
              borderRadius: "50%",
              backgroundColor: index === currentIndex ? "#333" : "#ddd",
              color: index === currentIndex ? "white" : "black",
              border: "none",
              cursor: "pointer",
            }}
          >
            {index + 1}
          </button>
        ))}
      </div>
    </div>
  );
};

export default ImageCarousel;

App.js

import ImageCarousel from './ImageCarousel'
export default function App() {
  const images = [
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel1.jpg',
    alt: 'nature',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel2.jpg',
    alt: 'Beach',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel3.jpg',
    alt: 'Yak',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel4.jpg',
    alt: 'Hay',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel5.jpg',
    alt: 'Plants',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel6.jpg',
    alt: 'Building',
  },
];
return (
  <>
    <h2>Image Carousel</h2>
     <ImageCarousel images={images} />
  </>
)
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Cards Carousel

Description
Build a card carousel component that displays one card at a time with navigation buttons (“Previous” and “Next” to scroll through a list of cards.

Requirements
* The component accepts a prop cards (an array of objects with title and description).
* Initially shows the first card with title and description.
* Clicking “Next” shows the next card, and “Previous” shows the previous one.
* Buttons should be disabled appropriately at the start/end of the list.
* Display the card number like “1 of 5”.
Constraints & Edge Cases
* If cards array is empty, show “No cards available”.
* Buttons must be disabled when there’s no next or previous card.
* Should handle single-card array gracefully.

https://namastedev.com/practice/cards-carousel

A

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

Carousel.js

import React, { useState } from "react";
import "./styles.css";

function Carousel({ cards = [] }) {
  const [currentIndex, setCurrentIndex] = useState(0);

  if (cards.length === 0) {
    return <div style={{ textAlign: "center", marginTop: "20px" }}>No cards available</div>;
  }

  const currentCard = cards[currentIndex];

  const handlePrevious = () => {
    if (currentIndex > 0) setCurrentIndex(currentIndex - 1);
  };

  const handleNext = () => {
    if (currentIndex < cards.length - 1) setCurrentIndex(currentIndex + 1);
  };

  return (
    <div
      style={{
        maxWidth: "400px",
        margin: "40px auto",
        padding: "20px",
        border: "1px solid #ccc",
        borderRadius: "10px",
        textAlign: "center",
      }}
    >
      <h2>{currentCard.title}</h2>
      <p>{currentCard.description}</p>

      <div style={{ marginTop: "20px" }}>
        <button onClick={handlePrevious} disabled={currentIndex === 0} style={{ marginRight: "10px" }}>
          Previous
        </button>
        <button onClick={handleNext} disabled={currentIndex === cards.length - 1}>
          Next
        </button>
      </div>

      <div style={{ marginTop: "10px", color: "#666" }}>
        {currentIndex + 1} of {cards.length}
      </div>
    </div>
  );
}

export default Carousel;

App.js

import Carousel from "./Carousel";

export default function App() {
  const cards = [
    { title: "Card 1", description: "Description for Card 1" },
    { title: "Card 2", description: "Description for Card 2" },
    { title: "Card 3", description: "Description for Card 3" },
  ];

  return <Carousel cards={cards} />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Sortable List

Description
Create a React component called SortableList that allows users to add new items to a list and sort the list either in ascending or descending order. The sorting action should be optimized using the useCallback hook to avoid unnecessary re-renders of the sorting function when the list or the order is updated.

You need to:
1. Implement an input field with the placeholder “Add a new item”
2. A button labelled “Add Item” to add new items to the list.
3. Ensure each item in the list has a unique id in the format item-<index>.
4. Implement two buttons labelled "Sort Ascending" and
"Sort Descending" to sort the list in ascending or descending order.
5. Use JavaScript's built-in .sort) method to sort the list items alphabetically.
6. Use useCallback to memoize the sorting function to avoid unnecessary re-creation of the function during re-renders.
7. The list should dynamically update after each operation (adding items or sorting).</index>

https://namastedev.com/practice/sortable-list

A

styles.css

.sortable-list-container {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border-radius: 8px;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:20px
  
}

.sortable-list-container h3 {
  text-align: center;
  color: #333;
}

.sortable-list-container input {
  width: calc(100% - 90px);
  padding: 8px;
  margin-right: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.sortable-list-container button {
  padding: 8px 12px;
  border: none;
  background-color: #007bff;
  color: white;
  border-radius: 4px;
  cursor: pointer;
  margin:5px
}

.sortable-list-container button:hover {
  background-color: #0056b3;
}

.sortable-list-container div {
  text-align: center;
  margin-bottom: 20px;
}

.list-items {
   background-color: #e9ecef;
  padding:20px;
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:start
}
``` 

SortableList.js

import React, { useState, useCallback } from ‘react’;
import ‘./styles.css’;

const SortableList = ({ items = [] }) => {
const [inputValue, setInputValue] = useState(‘’);
const [list, setList] = useState(items);

// Add new item to the list
const handleAddItem = () => {
if (inputValue.trim() === ‘’) return;
setList([…list, inputValue.trim()]);
setInputValue(‘’);
};

// Memoized ascending sort function
const sortAscending = useCallback(() => {
setList(prevList => […prevList].sort((a, b) => a.localeCompare(b)));
}, []);

// Memoized descending sort function
const sortDescending = useCallback(() => {
setList(prevList => […prevList].sort((a, b) => b.localeCompare(a)));
}, []);

return (
<div className="sortable-list-container">
<h3>Sortable List</h3>
<div style={{ display: ‘flex’, width: ‘100%’ }}>
<input
type=”text”
placeholder=”Add a new item”
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleAddItem}>Add Item</button>
</div>

  <div>
    <button onClick={sortAscending}>Sort Ascending</button>
    <button onClick={sortDescending}>Sort Descending</button>
  </div>

  <div className="list-items">
    {list.map((item, index) => (
      <div key={`item-${index}`} id={`item-${index}`}>
        {item}
      </div>
    ))}
  </div>
</div>   ); };

export default SortableList;
~~~

App.js

import SortableList from './SortableList'
const App = () => {
  const items = ['Apple', 'Banana', 'Orange', 'Grapes', 'Mango'];

  return <SortableList items={items} />;
};

export default App;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Star Rating

Description
You need to implement a star rating component where users can select a rating by clicking on stars. The rating should update dynamically, and there should be a reset button to clear the rating.

Requirements
* The component should display five stars *****.
* Clicking on a star should update the rating and highlight the selected stars.
* The highlighted stars should be yellow (#FFD700), and unselected stars should be gray (#CCCCC).
* There should be a reset button below the stars that resets the rating to 0. The button should be labelled
“Reset Rating”.
* Display the current rating below the stars with the text :
“Current Rating: X”, where X is the selected star rating.
* The default rating should be 0 (no stars selected).

https://namastedev.com/practice/star-rating

A

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

StarRating.js

// StarRating.js

import React, { useState } from "react";

function StarRating() {
  // Step 1: Create state variable for rating
  const [rating, setRating] = useState(0);

  // Function to render stars dynamically
  const renderStars = () => {
    const stars = [];
    for (let i = 1; i <= 5; i++) {
      stars.push(
        <span
          key={i}
          onClick={() => setRating(i)}
          style={{
            fontSize: "2rem",
            cursor: "pointer",
            color: i <= rating ? "#FFD700" : "#CCCCCC",
          }}
        >
          ★
        </span>
      );
    }
    return stars;
  };

  // Reset handler
  const resetRating = () => {
    setRating(0);
  };

  return (
    <div style={{ textAlign: "center", padding: "20px" }}>
      <h1>Star Rating</h1>
      <h3>by NamasteDev</h3>

      {/* Step 2: Render 5 stars */}
      <div>{renderStars()}</div>

      {/* Step 5: Display current rating */}
      <p>Current Rating: {rating}</p>

      {/* Step 6: Reset button */}
      <button onClick={resetRating}>Reset Rating</button>
    </div>
  );
}

export default StarRating;

App.js

import StarRating from "./StarRating";
import './styles.css'

export default function App() {
  return <StarRating />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Grid Lights

Requirements:
You are tasked with simulating a grid of lights that can be toggled on or off. The grid is initially in the “off” state. Each light in the grid can be toggled by clicking on it. When a light is toggled, the light itself and all adjacent lights (horizontally and vertically) also toggle their states.
The grid is composed of n x n cells, and each cell represents a light that can either be on (1) or off (0). The grid starts with all lights in the off state.
You need to implement a solution that allows toggling the lights and keeps track of the current state of the grid. Make sure to use inline css.

Component Structure:
* A single functional component named GridLights.
* Grid size n should be passed as a prop (default to 5 if not provided).
State Management:
* Use useState to manage the grid state.
* Maintain a 2D array to represent the current on/off state of each light.

Ul Behavior:
* Display the grid using simple square cells.
* A light in the “on” state should be visually different and have background color “gold”.
* A light in the “off” state should have a neutral background color “lightgray”.
* Clicking on a cell toggles the state of:
The clicked cell
The top neighbor (if it exists)
The bottom neighbor (if it exists)
The left neighbor (if it exists)
The right neighbor (if it exists)
* Each cell should have role=”cell”

User Interaction:
* Clicking on a cell updates the grid immediately.
* Ul should be responsive and update in real-time based on state.

https://namastedev.com/practice/grid-lights

A

GridLights.jsx

// GridLights.jsx
import React, { useState } from "react";

const GridLights = ({ n = 5 }) => {
  const [grid, setGrid] = useState(
    Array.from({ length: n }, () => Array(n).fill(0))
  );

  const toggleLight = (row, col) => {
    const newGrid = grid.map((r) => [...r]);

    const toggle = (i, j) => {
      if (i >= 0 && i < n && j >= 0 && j < n) {
        newGrid[i][j] = newGrid[i][j] === 1 ? 0 : 1;
      }
    };

    toggle(row, col);       // current
    toggle(row - 1, col);   // top
    toggle(row + 1, col);   // bottom
    toggle(row, col - 1);   // left
    toggle(row, col + 1);   // right

    setGrid(newGrid);
  };

  return (
    <div>
      <h2 style={{ textAlign: "center" }}>Grid Lights</h2>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: `repeat(${n}, 40px)`,
          gap: "5px",
          justifyContent: "center",
        }}
      >
        {grid.map((row, i) =>
          row.map((cell, j) => (
            <div
              key={`${i}-${j}`}
              role="cell"
              onClick={() => toggleLight(i, j)}
              style={{
                width: "40px",
                height: "40px",
                backgroundColor: cell === 1 ? "gold" : "lightgray",
                border: "1px solid #ccc",
                cursor: "pointer",
                transition: "background-color 0.2s ease",
              }}
            ></div>
          ))
        )}
      </div>
    </div>
  );
};

export default GridLights;

App.js

import GridLights from './GridLights'
export default function App() {
  return <GridLights/>
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Calculator

Create a simple responsive calculator component that performs basic arithmetic operations. It should feature interactive buttons and intuitive behavior for clear, backspace, and evaluation. The operators should be displayed using icons.

Requirements
* A container for visual calculator boundary.
* A display area implemented using an input field:
Placeholder text: “Enter expression”
Dynamically updates with user input
Displays both ongoing expressions and evaluation results
* Input must support the following characters:
Numbers: 0-9
Operators: +, -, *, /,%, v
Parentheses: ( and )
Decimal: *
* Button Grid:
A grid layout of numeric and operator buttons
Pressing = evaluates the expression
Clear button resets the entire input
Backspace button removes the last character only
* Use icons from lucide-react for enhanced visual clarity:
Clear - Trash
Backspace -> Delete
= > Equals
% -> Percent
/ -> Divide
→> Minus
> Plus
V -> Radical
* Invalid expressions should display Error in the input box

Edge Cases & Constraints
* Initial state: display is empty
* Invalid expressions should not break app
* Repeated operators must be handled gracefully
* Equal button should safely evaluate valid expressions
* Icons must respond on click and be testable
* Display should align text to the right and scroll if needed

Example Behaviors

// Example 1: User inputs "7 * 8"
Display: "7*8"
On "=" click → Display: "56"

// Example 2: Clear
Display: "56" → Click Clear (Trash icon) → ""

// Example 3: Backspace
Display: "5+" → Click Delete icon → "5"

// Example 4: Invalid
Display: "+" → "=" → Error

Testing Requirements
Data Test IDs (Required for Testing)

General Elements
* data-testid=”calc-container”. Test for rendering the container
* data-testid=”calc-display” - Calculator input display field with placeholder

Buttons
* data-testid=”btn-clear” - Clear all input
* data-testid=”btn-sqrt” - Square root operator (V)
* data-testid=”btn-modulus” - Modulus operator (%)
* data-testid=”btn-divide” - Division operator (/)
* data-testid=”btn-7” - Number 7
* data-testid=”btn-8” - Number 8
* data-testid=”btn-g” - Number 9
* data-testid=”btn-multiply” - Multiplication
operator ()
* data-testid=”btn-4” - Number 4
* data-testid=”btn-5” - Number 5
* data-testid=”btn-6” - Number 6
* data-testid=”btn-minus” - Subtraction operator
(-)
* data-testid=”btn-1” - Number 1
* data-testid=”btn-2” - Number 2
* data-testid=”btn-3” - Number 3
* data-testid=”btn-plus” - Addition operator (+)
* data-testid=”btn-0” - Number 0
* data-testid=”btn-dot” - Decimal point (
)
* data-testid=”btn-open” - Open parenthesis (
* data-testid=”btn-close” - Close parenthesis )
* data-testid=”btn-back” - Backspace/delete last character
* data-testid=”btn-equal” - Evaluate expression (=)

Icon-Specific Elements
* data-testid=”icon-clear” - Icon inside clear
(Trash)
* data-testid=”icon-backspace” - Icon inside
backspace (Delete)
* data-testid=”icon-equals” - Icon inside equals
button (Equals)
* data-testid=”icon-sqrt”- Icon inside Squareroot
button (Radical)
* data-testid=”icon-percent” - Icon inside
modulus button (Percent)
* data-testid=”icon-divide” - Icon inside divide
button (Divide)
* data-testid=”icon-multiply”- Icon inside
multiply button (X)
* data-testid=”icon-minus”- Icon inside minus
button (Minus)
* data-testid=”icon-plus” - Icon inside plus button
(Plus)

https://namastedev.com/practice/calculator

A

styles.css

body {
  margin: 0;
  font-family: "Poppins", sans-serif;
  background: linear-gradient(135deg, #f4f4f4, #dfe6e9);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

.calculator-container {
  background-color: #ffffff;
  padding: 30px 20px;
  border-radius: 20px;
  box-shadow: 0px 12px 24px rgba(0, 0, 0, 0.15);
  width: 320px;
  text-align: center;
}

.title {
  font-size: 25px;
  margin-bottom: 20px;
  margin-top: 8px;
  color: #22b691;
}

.display {
  width: 90%;
  height: 40px;
  font-size: 20px;
  padding: 10px;
  border-radius: 10px;
  border: 2px solid #000000;
  text-align: right;
  margin-bottom: 25px;
  background-color: #e6efe7;
  color: #2f3542;
}

.display::placeholder {
  color: #b2bec3;
}

.button-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

button {
  padding: 15px 0;
  font-size: 18px;
  border: none;
  border-radius: 10px;
  background-color: #d2f6ec;
  color: #2d3436;
  cursor: pointer;
  transition: all 0.2s ease;
}

button:hover {
  background-color: #a6dfc1;
  transform: scale(1.05);
}

/*special buttons*/
.clear-btn {
  background-color: #2d3436;
}

.clear-btn:hover {
  background-color: #000000;
}

.back-btn {
  background-color: #fd5a5a;
}

.back-btn:hover {
  background-color: #ff2b2b;
}

.equal-btn {
  grid-column: span 3;
  background-color: #00b894;
}

.equal-btn:hover {
  background-color: #019875;
}

/* Icon Styling for Lucide icons */
button svg {
  width: 20px;
  height: 20px;
  vertical-align: middle;
  stroke: #2d3436;
}

/* Icon colors for special buttons */
.clear-btn svg {
  stroke: #ffffff;
}

.back-btn svg {
  stroke: #ffffff;
}

.equal-btn svg {
  stroke: #ffffff;
}

Calculator.js

import React, { useState } from "react";
import "./styles.css";
import {
  Trash,
  Delete,
  Equal as Equals,
  Percent,
  Divide,
  Minus,
  Plus,
  Radical,
  X,
} from "lucide-react";

function Calculator() {
const [expression, setExpression] = useState("");

  const appendToExpression = (value) => {
    setExpression((prev) => prev + value);
  };

  const handleBackspace = () => {
    setExpression((prev) => prev.slice(0, -1));
  };

  const handleClear = () => {
    setExpression("");
  };

  const handleEvaluate = () => {
    try {
      // Replace √ with Math.sqrt syntax
      let sanitized = expression.replace(/v/g, "Math.sqrt");

      // Evaluate
      const result = eval(sanitized); // Safe here because user controls input
      setExpression(result.toString());
    } catch {
      setExpression("Error");
    }
  };

  return (
    <div className="calculator-container" data-testid="calc-container">
      <h1 className="title">Simple Calculator</h1>
      <input
        className="display"
        data-testid="calc-display"
        placeholder="Enter expression"
        readOnly
        value={expression}
      />

      <div className="button-grid">
        <button className="clear-btn" data-testid="btn-clear" onClick={handleClear}>
          <Trash data-testid="icon-clear" />
        </button>
        <button className="icon-sqrt" data-testid="btn-sqrt" onClick={() => appendToExpression("v")}>
          <Radical data-testid="icon-sqrt" />
        </button>
        <button
          data-testid="btn-modulus"
          onClick={() => appendToExpression("%")}
        >
          <Percent data-testid="icon-percent" />
        </button>
         <button
          data-testid="btn-divide"
          onClick={() => appendToExpression("/")}
        >
          <Divide data-testid="icon-divide" />
        </button>

        <button data-testid="btn-7" onClick={() => appendToExpression("7")}>
          7
        </button>
        <button data-testid="btn-8" onClick={() => appendToExpression("8")}>
          8
        </button>
        <button data-testid="btn-g" onClick={() => appendToExpression("9")}>
          9
        </button>
        <button
          data-testid="btn-multiply"
          onClick={() => appendToExpression("*")}
        >
          <X data-testid="icon-multiply" />
        </button>

        <button data-testid="btn-4" onClick={() => appendToExpression("4")}>
          4
        </button>
        <button data-testid="btn-5" onClick={() => appendToExpression("5")}>
          5
        </button>
        <button data-testid="btn-6" onClick={() => appendToExpression("6")}>
          6
        </button>
        <button
          data-testid="btn-minus"
          onClick={() => appendToExpression("-")}
        >
          <Minus data-testid="icon-minus" />
        </button>

        <button data-testid="btn-1" onClick={() => appendToExpression("1")}>
          1
        </button>
        <button data-testid="btn-2" onClick={() => appendToExpression("2")}>
          2
        </button>
        <button data-testid="btn-3" onClick={() => appendToExpression("3")}>
          3
        </button>
        <button
          data-testid="btn-plus"
          onClick={() => appendToExpression("+")}
        >
          <Plus data-testid="icon-plus" />
        </button>

        <button data-testid="btn-0" onClick={() => appendToExpression("0")}>
          0
        </button>
        <button data-testid="btn-dot" onClick={() => appendToExpression(".")}>
          .
        </button>
        <button
          data-testid="btn-open"
          onClick={() => appendToExpression("(")}
        >
          (
        </button>
        <button
          data-testid="btn-close"
          onClick={() => appendToExpression(")")}
        >
          )
        </button>

        <button
          className="back-btn"
          data-testid="btn-back"
          onClick={handleBackspace}
        >
          <Delete data-testid="icon-backspace" />
        </button>
        <button
          className="equal-btn"
          data-testid="btn-equal"
          onClick={handleEvaluate}
        >
          <Equals data-testid="icon-equals" />
        </button>
      </div>
    </div>
  );
}

export default Calculator;

App.js

import Calculator from './Calculator.js'
export default function App() {
  return <Calculator/>
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Tic Tac Toe

Build a simple Tic Tac Toe game using React. This game allows two players to take turns and play on a 3x3 board. The goal is to get three of the same symbol (X or O) in a row (horizontally, vertically, or diagonally).

Functional Requirements:
1. Render a 3x3 grid of squares.
2. Each player takes a turn placing “X” or “O”.
3. Show a message like “Next Player: X” or “Next Player: O”.
4. Detect the winner or a draw and show the result.
5. Disable all squares after a win or draw.
6. Include a “Restart Game” button to reset the board. The restart button must have an id=”restart”.
7. Each cell must have an id in the format cell-o to cell-8, corresponding to its position.
8. You must display a message showing the current status of the game. This message should appear at all times and clearly indicate one of the following:
9. Possible Status Messages:
* Next Player: X- when it’s X’s turn.
* Next Player: 0 - when it’s O’s turn.
* Winner: X - when player X wins.
* Winner: 0 - when player O wins.
* It’s a Draw! - when all 9 cells are filled and there’s no winner.
10. The element that displays this message must have the HTML id=”status”, so it can be accessed easily in automated tests.

https://namastedev.com/practice/tic-tac-toe

A

styles.css

.game {
  text-align: center;
  margin-top: 50px;
  font-family: sans-serif;
}

.board {
  display: grid;
  grid-template-columns: repeat(3, 80px);
  grid-gap: 10px;
  justify-content: center;
  margin: 20px auto;
}

.square {
  width: 80px;
  height: 80px;
  font-size: 2rem;
  font-weight: bold;
  cursor: pointer;
  background-color: #f0f0f0;
  border: 2px solid #999;
  border-radius: 8px;
}

.restart-button {
  margin-top: 20px;
  padding: 10px 20px;
  font-size: 1rem;
}

TicTacToe.js

import React, { useState } from "react";
import "./styles.css";

function TicTacToe() {
  const initialBoard = Array(9).fill(null);
  const [board, setBoard] = useState(initialBoard);
  const [isXNext, setIsXNext] = useState(true);
  const winner = calculateWinner(board);
  const isDraw = !winner && board.every((cell) => cell !== null);

  // Status Message
  let statusMessage = "";
  if (winner) {
    statusMessage = `Winner: ${winner}`;
  } else if (isDraw) {
    statusMessage = "It's a Draw!";
  } else {
    statusMessage = `Next Player: ${isXNext ? "X" : "O"}`;
  }

  const handleClick = (index) => {
    if (board[index] || winner || isDraw) return; // Disable moves after game ends

    const newBoard = [...board];
    newBoard[index] = isXNext ? "X" : "O";
    setBoard(newBoard);
    setIsXNext(!isXNext);
  };

  const restartGame = () => {
    setBoard(initialBoard);
    setIsXNext(true);
  };

  return (
    <div className="game">
      <h1>Tic Tac Toe</h1>

      {/* STATUS MESSAGE */}
      <h2 id="status">{statusMessage}</h2>

      {/* GAME BOARD */}
      <div className="board">
        {board.map((value, index) => (
          <button
            key={index}
            id={`cell-${index}`}
            className="square"
            onClick={() => handleClick(index)}
            disabled={winner || isDraw}
          >
            {value}
          </button>
        ))}
      </div>

      {/* RESTART BUTTON */}
      <button id="restart" className="restart-button" onClick={restartGame}>
        Restart Game
      </button>
    </div>
  );
}

// Helper function to check winner
function calculateWinner(board) {
  const winningCombos = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  for (let [a, b, c] of winningCombos) {
    if (board[a] && board[a] === board[b] && board[a] === board[c]) {
      return board[a];
    }
  }
  return null;
}

export default TicTacToe;

App.js

import TicTacToe from './TicTacToe'
export default function App() {
  return <TicTacToe/>
}
22
Q

Dice Roller

Create a Dice Roller Component that simulates rolling a dice when a button is clicked. The dice should display a random number between 1 and 6.

Requirements
1. The component should have a button labeled “Roll Dice”.
2. Clicking the button should generate a random number between 1 and 6.
3. The rolled number should be displayed on the screen with text =”🎲 diceValue”.
4. If the Roll Dice button is not clicked, then show a message “Click to roll!”
5. The Ul should include a dice-like representation (optional).
Constraints & Edge Cases
* Constraint 1: The rolled number should always be between 1 and 6.
* Constraint 2: Ensure the result updates correctly on every button click.
* Edge Case 1: Handle cases where the button is clicked multiple times quickly.
* Edge Case 2: Ensure Ul updates correctly when the dice is rolled.

https://namastedev.com/practice/dice-roller

A

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;
}.dice-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

button {
  padding: 10px 20px;
  font-size: 1rem;
  margin-bottom: 20px;
  cursor: pointer;
}

.dice-display p {
  font-size: 1.2rem;
  margin-top: 10px;
}

/* Dice UL Grid */
.dice-grid {
  display: grid;
  grid-template-columns: repeat(3, 20px);
  grid-template-rows: repeat(3, 20px);
  gap: 5px;
  list-style: none;
  padding: 0;
  margin: 10px 0;
}

.dice-grid li {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #eee;
}

.dice-grid li.dot {
  background-color: #333;
}

DiceRoller.js

import React, { useState } from "react";
import "./styles.css";

function DiceRoller() {
  const [diceValue, setDiceValue] = useState(null);

  const rollDice = () => {
    // Generate a random number between 1 and 6
    const value = Math.floor(Math.random() * 6) + 1;
    setDiceValue(value);
  };

  // // Dice dots representation
  // const renderDiceFace = (value) => {
  //   const dots = {
  //     1: [4],
  //     2: [0, 8],
  //     3: [0, 4, 8],
  //     4: [0, 2, 6, 8],
  //     5: [0, 2, 4, 6, 8],
  //     6: [0, 2, 3, 5, 6, 8],
  //   };

  //   return (
  //     <ul className="dice-grid">
  //       {Array(9)
  //         .fill(0)
  //         .map((_, index) => (
  //           <li
  //             key={index}
  //             className={dots[value]?.includes(index) ? "dot" : ""}
  //           ></li>
  //         ))}
  //     </ul>
  //   );
  // };

  // const getDieSymbol = (value) => {
  //   const symbols = ["⚀", "⚁", "⚂", "⚃", "⚄", "⚅"];
  //   return symbols[value - 1] || "";
  // };

  return (
    <div className="dice-container">
      <h1>Dice Roller</h1>

      <button onClick={rollDice}>Roll Dice</button>

      <div className="dice-display">
        {diceValue ? (
          <>
            {
              // renderDiceFace(diceValue)
            }
            <p>🎲 {diceValue}</p>
          </>
        ) : (
          <p>Click to roll!</p>
        )}
      </div>
    </div>
  );
}

export default DiceRoller;

App.js

import DiceRoller from "./DiceRoller";

export default function App() {
    return <DiceRoller />;
}
23
Q

Typewriter Message

Animation
* Display text character by character with 100ms delay for authentic typewriter feel
* Show animated blinking cursor during typing animation for visual appeal

Controls
* Include “Start” button to initiate the typewriter effect
* Include “Skip” button to instantly reveal the full message for impatient users
* Include “Next” button to cycle through different inspirational messages
* Show message counter (e.g., “Message 1 of 5”) to track progress
* Disable buttons appropriately during animation to prevent conflicts

Functionality
* Clear Interval when animation completes or is skipped for proper cleanup
* Use useEffect and setinterval for precise timing control
* Implement string sileing for character-by-character display
* Manage multiple messages with seamless cycling functionality

Required Elements and Attributes for Testing
Message Display
* Must contain text element showing partial or full message

Blinking Cursor
* Must have animated cursor during typing

Buttons
* Start Button → Must contain visible text “Start” and have onClick handler
* Skip Button → Must contain visible text “Skip” and have onClick handler
* Next Button → Must contain visible text “Next” and have onClick handler

Message Counter
* Must display “Message X of Y” format
Button States
* Buttons must be disabled during typing animation

Animation Speed
* Characters must appear with 100ms interval

https://namastedev.com/practice/typewriter-message

A

styles.css

.typewriter-container {
  text-align: center;
  font-family: "Courier New", monospace;
  margin-top: 40px;
  max-width: 800px;
  margin-left: auto;
  margin-right: auto;
  padding: 20px;
  background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
  border-radius: 15px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}

.typewriter-container h1 {
  color: #ecf0f1;
  font-size: 2.5rem;
  margin-bottom: 30px;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}

.message-display {
  background: rgba(0, 0, 0, 0.8);
  border: 2px solid #3498db;
  border-radius: 10px;
  padding: 30px;
  margin: 20px 0;
  min-height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.displayed-text {
  font-size: 1.4rem;
  color: #2ecc71;
  margin: 0;
  line-height: 1.6;
  text-align: left;
  font-family: "Courier New", monospace;
}

.cursor {
  color: #e74c3c;
  font-weight: bold;
  animation: blink 1s infinite;
  margin-left: 2px;
}

@keyframes blink {
  0%,
  50% {
    opacity: 1;
  }
  51%,
  100% {
    opacity: 0;
  }
}

.controls {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin: 30px 0;
  flex-wrap: wrap;
}

.controls button {
  padding: 12px 24px;
  font-size: 1.1rem;
  font-weight: bold;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-family: "Courier New", monospace;
  min-width: 120px;
}

.start-button {
  background: #27ae60;
  color: white;
}

.start-button:hover:not(:disabled) {
  background: #229954;
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(39, 174, 96, 0.4);
}

.skip-button {
  background: #e67e22;
  color: white;
}

.skip-button:hover {
  background: #d35400;
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(230, 126, 34, 0.4);
}

.next-button {
  background: #3498db;
  color: white;
}

.next-button:hover:not(:disabled) {
  background: #2980b9;
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(52, 152, 219, 0.4);
}

.controls button:disabled {
  background: #95a5a6;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.message-info {
  margin-top: 30px;
  color: #bdc3c7;
}

.message-info p {
  margin: 10px 0;
  font-size: 1rem;
}

.instruction {
  color: #ecf0f1;
  font-style: italic;
  font-size: 1.1rem;
}

/* Responsive design */
@media (max-width: 768px) {
  .typewriter-container {
    margin: 20px;
    padding: 15px;
  }

  .typewriter-container h1 {
    font-size: 2rem;
  }

  .displayed-text {
    font-size: 1.2rem;
  }

  .controls {
    flex-direction: column;
    align-items: center;
  }

  .controls button {
    width: 200px;
  }
}

App.js

import React from "react";
import { TypeWriterMessage } from "./TypeWriterMessage.js";
import "./styles.css";

function App() {
  return (
    <div className="app-wrapper">
      <TypeWriterMessage />
    </div>
  );
}

export default App;

TypeWriterMessage.js

import React, { useState, useEffect, useRef } from "react";
import "./styles.css";

const messages = [
  "Hello, welcome to the typewriter effect!",
  "This demonstrates useEffect and setInterval in React.",
  "Watch as each character appears one by one.",
  "You can skip the animation if you're impatient!",
  "Thanks for watching the typewriter in action!",
];

export function TypeWriterMessage() {
  const [currentMessageIndex, setCurrentMessageIndex] = useState(0);
  const [displayedText, setDisplayedText] = useState("");
  const [isTyping, setIsTyping] = useState(false);
  const [showSkip, setShowSkip] = useState(false);

  const intervalRef = useRef(null);
  const indexRef = useRef(0); // <-- FIX: stable index

  const startTyping = () => {
    if (isTyping) return;

    clearInterval(intervalRef.current); // <-- FIX: avoid overlapping timers

    setDisplayedText("");
    indexRef.current = 0; // start from first character every time
    setIsTyping(true);
    setShowSkip(true);
  };

  const skipTyping = () => {
    clearInterval(intervalRef.current);

    const fullMessage = messages[currentMessageIndex];
    setDisplayedText(fullMessage);

    setIsTyping(false);
    setShowSkip(false);
  };

  const nextMessage = () => {
    clearInterval(intervalRef.current);

    setDisplayedText("");
    indexRef.current = 0;
    setIsTyping(false);
    setShowSkip(false);

    setCurrentMessageIndex((prev) => (prev + 1) % messages.length);
  };

  useEffect(() => {
    if (!isTyping) return;

    clearInterval(intervalRef.current); // prevent duplicates

    const fullMessage = messages[currentMessageIndex];

    intervalRef.current = setInterval(() => {
      const i = indexRef.current;

      if (i >= fullMessage.length) {
        clearInterval(intervalRef.current);
        setIsTyping(false);
        setShowSkip(false);
        return;
      }

      setDisplayedText((prev) => prev + fullMessage[i]);
      indexRef.current += 1;
    }, 100);

    return () => clearInterval(intervalRef.current);
  }, [isTyping, currentMessageIndex]);

  return (
    <div className="typewriter-container">
      <h1>Typewriter Effect</h1>

      <div className="message-display">
        <p className="displayed-text">{displayedText}</p>
        {isTyping && <span className="cursor">|</span>}
      </div>

      <div className="controls">
        <button
          onClick={startTyping}
          className="start-button"
          disabled={isTyping}
        >
          Start
        </button>

        {showSkip && (
          <button
            onClick={skipTyping}
            className="skip-button"
            disabled={!isTyping}
          >
            Skip
          </button>
        )}

        <button
          onClick={nextMessage}
          className="next-button"
          disabled={isTyping}
        >
          Next
        </button>
      </div>

      <div className="message-info">
        <p>
          Message {currentMessageIndex + 1} of {messages.length}
        </p>
        <p className="instruction">
          Watch the typewriter effect or use the Skip button to see the full
          message instantly!
        </p>
      </div>
    </div>
  );
}
24
Q

Word Counter

Build a Word Frequency Counter that dynamically analyzes user input text and displays how often each word appears. The counter is case-insensitive, ignores special characters, and sorts the output in descending order of frequency.

Things to do
* Create a textarea where users can type or paste any text.
* Every time the text changes, update the word count list in real-time.
* Case-insensitive word matching
* Ignore symbols, numbers, punctuation, and extra white spaces.
* Sorts words by their frequency (most used on top)
* Each word should be shown with the number of times it occurs (e.g., hello:
3 Times).

Example
Input:

React,
React Testing NamasteDev!

Output:

react count: 2
namastedev count: 1
testing count: 1

How It Works
1. User types into the textarea
2. On each character change:
* Text is cleaned: punctuation is removed, all words are lowercased.
* Words are split and counted.
* Results are sorted by frequency and displayed as a list.

Testing Instructions
Please use the following data-testid attributes in your React component:
* textarea → for the textarea input
* result-list → for the textarea input
* word-(word} → for each word e.g “word-react”

https://namastedev.com/practice/word-counter

A

styles.css

.wordCounter {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container {
  padding: 10px;
}
.textarea {
  width: 300px;
  height: 40px;
  padding: 10px 15px;
}
ul li {
  list-style-type: square;
}
li {
  text-align: left;
  margin: 5px 0;
}

App.js

import WordCounter from './WordCounter.js'
export default function App() {
  return <WordCounter/>
}

WordCounter.js

import { useState, useEffect } from "react";

function WordCounter() {
  const [text, setText] = useState("");
  const [count, setCount] = useState([]);

  // Count Logic
  function handleCount(inputText) {
    // 1. Convert to lowercase
    let cleaned = inputText.toLowerCase();

    // 2. Remove everything except letters & spaces
    cleaned = cleaned.replace(/[^a-z\s]/g, " ");

    // 3. Split into words, filter out empty strings
    const words = cleaned.split(/\s+/).filter(Boolean);

    // 4. Count occurrences
    const freq = {};
    words.forEach((w) => {
      freq[w] = (freq[w] || 0) + 1;
    });

    // 5. Convert to array & sort by frequency
    const sorted = Object.entries(freq).sort((a, b) => b[1] - a[1]);

    setCount(sorted);
  }

  useEffect(() => {
    handleCount(text);
  }, [text]);

  return (
    <div className="wordCounter">
      <h1>Word Counter</h1>

      <div className="container">
        <textarea
          className="textarea"
          placeholder="Type your text here"
          data-testid="textarea"
          value={text}
          onChange={(e) => setText(e.target.value)}
        ></textarea>

        <div className="results">
          <h3>Word Frequencies</h3>
          <ul data-testid="result-list">
            {count.map(([word, countValue]) => (
              <li key={word} data-testid={`word-${word}`}>
                <strong>{word}</strong>: {countValue} Times
              </li>
            ))}
          </ul>
        </div>
      </div>
    </div>
  );
}
export default WordCounter;
25
# **Pawn Moves** Build a React component that displays an 8x8 chessboard. When the user hovers over any square, it shows all valld forward cells a pawn could move to from that square. All highlights must clear when the hover ends or moves to another square. **Requirements** 1. Display an 8x8 grid (64 total cells), styled as a chessboard. 2. Each square must have the attribute role="gridcell" for accessibility and testability. 3. When the user hovers over a square: That square should show a pawn icon (♙) and get the . hovered class. All valid forward move squares should be highlighted with the - pawn-move class. 4. For the pawn's movement: It moves upward (toward decreasing row index). From row 6 (its initial row), it can move 1 or 2 steps forward. From rows 1 to 5, it can move 1 step forward. From row 0 or 7, it cannot move (no squares should be highlighted). 5. When the mouse leaves a cell: All highlights, including the hovered cell and pawn-move cells, should disappear. **Edge Cases** * Hovering over square [4, 4] → Should highlight only one square ahead ([3, 41), because the pawn is in a normal mid-board position, not the starting row. * Hovering over square [6, 4] → Should highlight two squares ahead ([5, 4] and [4, 41). Pawns on the starting row (row 6) can move one or two steps forward. * Hovering over square [7, 4] → Should not highlight any move squares, since a pawn on the last rank cannot move forward. * Mouse leaves any square → All highlighted cells and pawn move Indicators should be cleared immediately. * Hovering quickly over different squares → Only the most recently hovered square and its valid moves should be highlighted. Prevlous highlights must be removed instantly. ## Footnote https://namastedev.com/practice/pawn-moves
styles.css ``` body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f0f0f0; } .board { display: grid; grid-template-columns: repeat(8, 40px); grid-template-rows: repeat(8, 40px); border: 2px solid #333; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); } .cell { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; box-sizing: border-box; transition: background-color 0.3s; } .light { background-color: #f0d9b5; } .dark { background-color: #b58863; } .hovered { background-color: lightblue !important; } .pawn-move { background-color: darkblue !important; } .pawn-icon { font-size: 28px; font-weight: bold; color: black; font-family: "Segoe UI Symbol", "Arial Unicode MS", "Noto Sans Symbols", sans-serif; pointer-events: none; } ``` App.js ``` import PawnBoard from './PawnBoard' export default function App() { return } ``` PawnBoard.js ``` import React, { useState } from "react"; const boardSize = 8; export default function PawnBoard() { const [hovered, setHovered] = useState(null); // { row, col } const [moves, setMoves] = useState([]); // list of { row, col } // Compute pawn forward moves based on hover location const getPawnMoves = (row, col) => { const moves = []; // Pawn moves "up" → decreasing row index const oneStep = row - 1; const twoStep = row - 2; // Row 7 or row 0 → cannot move if (row === 7 || row === 0) return moves; // If from starting row (row 6), allow two steps if (row === 6) { if (oneStep >= 0) moves.push({ row: oneStep, col }); if (twoStep >= 0) moves.push({ row: twoStep, col }); return moves; } // Normal move: one step if (oneStep >= 0) moves.push({ row: oneStep, col }); return moves; }; const handleHover = (row, col) => { setHovered({ row, col }); setMoves(getPawnMoves(row, col)); }; const handleLeave = () => { setHovered(null); setMoves([]); }; return (
{Array.from({ length: boardSize }).map((_, row) => Array.from({ length: boardSize }).map((_, col) => { const isLight = (row + col) % 2 === 0; const isHovered = hovered?.row === row && hovered?.col === col; const isMoveSquare = moves.some(m => m.row === row && m.col === col); return (
handleHover(row, col)} onMouseLeave={handleLeave} > {isHovered && }
); }) )}
); } ```
26
# **Pin Items** **Problem Statement** Create a React application that displays a list of items with the ability to "pin" individual items. Pinning an item moves it to the top of the list, and unpinning moves it back to its original position below pinned items. Each item has a checkbox to toggle the pinned state. **Requirements** 1. Display a title: Pin Items To Top. 2. Display a list of Items: Initially, 8 items are shown with text labels. 3. Pin/unpin functionality: Each item has a checkbox to toggle its pinned status. Pinned items appear at the top of the list, preserving the order in which they were pinned. Unpinned items appear below pinned items, preserving their original order. 4. Ul and Interaction: Clicking the checkbox toggles the pinned state of the item. The pinned items should have a distinct style (e.g., background color, font weight). The list should re-render immediately after pin/unpin to reflect the changes. 5. Accessibility & Testablilty: Use appropriate data-testid attributes for key elements to support automated testing. **Edge Cases and Constraints** * Pinning multiple items maintains their relative pinned order (the order they appear after pinning). * Unpinning items restores their position among unpinned items without disturbing other items. * No item can be pinned more than once simultaneously. * The initial state should have no items pinned. * The app should efficiently update the Ul on toggle without full reload. * Maximum number of items is 8 in the current scope but should support easy scalability. **Data Test IDs (for Testing)** * Main title (heading) » data-testid="main-title" Description: The heading/title of the app * Item list ( data-testid="pin-checkbox-1" * Pin checkbox for item 2: "Call Alice" > data-testid="pin-checkbox- 2" * Pin checkbox for item 3: "Meeting with Bob" * data-testid="pin-checkbox-3" * Pin checkbox for item 4: "Pay electricity bIll" > data-testid="pin-checkbox-4" * Pin checkbox for Item 5: "Read a book" * data-testid="pin-checkbox-5" * Pin checkbox for item 6: "Go for a walk" > data-testid="pin-checkbox-6" * Pin checkbox for item 7: "Fix bug #234" > data-testid="pin-checkbox-7" * Pin checkbox for item 8: "Revlew pull requests" > data-testid="pin-checkbox-8" ## Footnote https://namastedev.com/practice/pin-items
styles.css ``` /* Base styling */ body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(120deg, #f0f4f8, #d9e2ec); margin: 0; padding: 0; } /* Container */ .container { background: #ffffff; padding: 2rem; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease; } .container:hover { transform: scale(1.01); } /* Title */ h1 { text-align: center; color: #2f3e46; font-size: 2rem; margin-bottom: 1.5rem; } /* List */ ul { list-style-type: none; padding: 0; margin: 0; } li { display: flex; align-items: center; justify-content: space-between; background: #f8f9fa; margin: 0.5rem 0; padding: 0.5rem 1rem; border-radius: 12px; border: 1px solid #dfe3e6; transition: background 0.3s; } li:hover { background: #e6f0ff; } li.pinned { background: rgb(10, 150, 150); border-color: rgb(4, 150, 150); font-weight: 400; color: #856404; } /* Label and Checkbox */ label { display: flex; align-items: center; gap: 0.75rem; font-size: 14px; color: #343a40; cursor: pointer; width: 100%; } /* Checkbox Custom Styling */ input[type="checkbox"] { accent-color: #434943; width: 1rem; height: 1rem; cursor: pointer; } ``` App.js ``` import PinItems from './PinItems' export default function App() { return } ``` PinItems.js ``` import React, { useState } from "react"; import "./styles.css"; export default function PinItems() { const initialItems = [ { id: 1, text: "Buy groceries", pinned: false }, { id: 2, text: "Call Alice", pinned: false }, { id: 3, text: "Meeting with Bob", pinned: false }, { id: 4, text: "Pay electricity bill", pinned: false }, { id: 5, text: "Read a book", pinned: false }, { id: 6, text: "Go for a walk", pinned: false }, { id: 7, text: "Fix bug #234", pinned: false }, { id: 8, text: "Review pull requests", pinned: false }, ]; const [items, setItems] = useState(initialItems); // Toggle pinned state const handlePinToggle = (id) => { setItems((prevItems) => prevItems.map((item) => item.id === id ? { ...item, pinned: !item.pinned } : item ) ); }; // Separate pinned + unpinned items while keeping original order const pinnedItems = items.filter((item) => item.pinned); const unpinnedItems = items.filter((item) => !item.pinned); // Final ordered list const orderedItems = [...pinnedItems, ...unpinnedItems]; return (

Pin Items To Top

    {orderedItems.map((item) => (
  • ))}
); } ```
27
# **Billing Counter** ## Footnote https://namastedev.com/practice/billing-counter
28
# **King Moves** ## Footnote https://namastedev.com/practice/king-moves
29
# **Queen Moves** ## Footnote https://namastedev.com/practice/queen-moves
30
# **Paginated Article Bookmark Viewer** ## Footnote https://namastedev.com/practice/paginated-article-bookmark-viewer
31
# **Generate Password** ## Footnote https://namastedev.com/practice/generate-password
32
# **Drag and Drop II** ## Footnote https://namastedev.com/practice/drag-and-drop-ii
33
# **Color Code Game** ## Footnote https://namastedev.com/practice/color-code-game
34
# **Expense Tracker** ## Footnote https://namastedev.com/practice/expense-tracker
35
# **Markdown Editor** ## Footnote https://namastedev.com/practice/markdown-editor
36
# **Draw Circles** ## Footnote https://namastedev.com/practice/draw-circles
37
# **JSON Formatter and Validator** ## Footnote https://namastedev.com/practice/json-formatter-and-validator
38
# **Rook Moves** ## Footnote https://namastedev.com/practice/rook-moves
39
# **Quiz App** ## Footnote https://namastedev.com/practice/quiz-app
40
# **Captcha Generator** ## Footnote https://namastedev.com/practice/captcha-generator
41
# **Rock Paper Scissor** ## Footnote https://namastedev.com/practice/rock-paper-scissor
42
# **Cinema Hall** ## Footnote https://namastedev.com/practice/cinema-hall
43
# **Grid Lights II** ## Footnote https://namastedev.com/practice/grid-lights-ii
44
# **Bishop Moves** ## Footnote https://namastedev.com/practice/bishop-moves
45
# **Kanban Board** ## Footnote https://namastedev.com/practice/kanban-board
46
# **Temperature Convertor** ## Footnote https://namastedev.com/practice/temperature-convertor
47
# **Undo Redo** ## Footnote https://namastedev.com/practice/undo-redo
48
# **Emoji Replacer** ## Footnote https://namastedev.com/practice/emoji-replacer
49
# **Knight moves** ## Footnote https://namastedev.com/practice/knight-moves
50
# **Social Share** ## Footnote https://namastedev.com/practice/social-share
51
# **Traffic Lights** ## Footnote https://namastedev.com/practice/traffic-lights