← Back to Home

⚚ Interactive Lab

Your Interactive Playground

Hands-on challenges that teach by doing. Try breaking things, seeing errors, and learning from mistakes in real time. Each exercise is designed to reinforce concepts you've learned.

🔳 CSS Grid Builder

Create a responsive grid layout with your favorite photo gallery. Learn about grids, columns, rows, and responsive design patterns without frameworks.

Challenge

Build a 3-column grid for a photo gallery that collapses to 1-column on narrow screens using CSS media queries.

💡 Hint

Use display: grid; with grid-template-columns: repeat(3, 1fr);. Add a media query for screens under 600px to show 1 column.

/* Grid layout */ .gallery { display: grid; gap: 1rem; grid-template-columns: repeat(3, 1fr); /* Responsive */ @media (max-width: 600px) { grid-template-columns: 1fr; } }

🎯 Solutions

Try experimenting with the grid properties. What happens if you change gap size? Test responsive breakpoints. Break your grid—then fix it!

React Event Handlers

Learn about React event handling and state updates. Create interactive UI elements that respond to user actions, demonstrating state management.

Challenge

Create a counter component that increments/decrements on button clicks, displays a message when count >= 5, and resets on click.

💡 Hint

Use useState for the counter. Use onClick handlers. Show conditional text using ternary or {} blocks.

import React, { useState } from 'react'; const Counter = () => { const [count, setCount] = useState(0); const increment = () => { if (count < 5) { setCount(prev => prev + 1); } else { setCount(0); } }; return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); };

🎯 Solutions

Notice how the state update is conditional. React prevents out-of-bounds updates. Try adding more features to the counter!

💙 TypeScript Type Safety

Experience TypeScript's type safety firsthand. Break your code with type errors and see how TypeScript helps you find bugs before runtime.

Challenge

Create an interface for a User object. Add a function that accepts a User and logs its name. Intentionally type errors to see compiler messages.

💡 Hint

Define an interface with interface keyword. Add properties. The compiler will catch errors where types don't match.

interface User { id: number; name: string; email: string; } const createUser = (user: User): void => { // This works console.log(`User: ${user.name}`); // This won't compile (error!): function wrong(user: string) { console.log(user); } };

🎯 Solutions

TypeScript shows you exactly where you're wrong. Fix the type mismatch—see how powerful type checking is!

🌐 API Explorer

Explore real APIs and learn about async operations. Fetch data, handle loading states, and deal with errors when building production applications.

Challenge

Use the JSONPlaceholder API to fetch users. Display a loading message while the request is processing, show the user list, and handle network errors gracefully.

💡 Hint

Use fetch('https://jsonplaceholder.typicode.com/users'). Show a loading spinner while !user exists. Handle errors with try/catch.

async function fetchUsers() { try { const response = await fetch('https://jsonplaceholder.typicode.com/users'); const data = await response.json(); if (data) { render(data); } else { showError('No users found'); } } catch (error) { handleError(error); } }

🎯 Solutions

Real-world API work involves loading states, error handling, and edge cases. Practice handling all scenarios!