Week 5

State with useState

Render and commit lifecycle

Event Handling

Forms

Practice

Assignment

Front end Track

Week 5 Assignment: Adding Interactivity to Your Portfolio

Focus: useState, event handling, controlled forms, lifting state up

Description

Your portfolio is a working React app. Right now it's static — the content renders, but nothing responds to user interaction. This week you add the layer that makes it feel alive: a dark mode toggle that actually tracks its own state, a contact form with controlled inputs and validation, and a projects filter that lets visitors narrow down what they see.

By the end of this assignment, your week 6 starting point will be a React portfolio with components for each section, a dark mode toggle using useState, and a contact form with controlled inputs and basic validation — exactly what week 6 builds on.

What you're building on

Your week 4 portfolio should have:

You're not starting over — you're extending what's already there.

Requirements

1. Upgrade the dark mode toggle with useState

In week 4 the toggle changed the DOM directly. Replace that with React state so the button label stays in sync:

export default function Header() {
  const [isDark, setIsDark] = useState(false);

  function handleThemeToggle() {
    setIsDark(!isDark);
    document.body.classList.toggle('dark-mode');
  }

  return (
    <header>
      {/* your name, tagline, image */}
      <button onClick={handleThemeToggle}>
        {isDark ? 'Light mode' : 'Dark mode'}
      </button>
    </header>
  );
}

Requirements:

2. Build a controlled contact form

Replace your week 4 form with a fully controlled version. Every input is driven by React state.

interface FormData {
  name: string;
  email: string;
  message: string;
}

interface FormErrors {
  name?: string;
  email?: string;
  message?: string;
}

export default function Contact() {
  const [formData, setFormData] = useState<FormData>({
    name: '',
    email: '',
    message: '',
  });
  const [errors, setErrors] = useState<FormErrors>({});
  const [submitted, setSubmitted] = useState(false);

  // your handlers here
}

Requirements:

<aside> ⚠️

Do not put validation logic inside the onChange handlers. Validate only on submit — checking on every keystroke makes the form feel hostile before the user has finished typing.

</aside>

3. Add a projects filter

Give visitors a way to filter your project list by technology. This requires lifting state up: the filter lives in the parent that owns both the filter controls and the project list.

const projects: Project[] = [
  {
    id: 1,
    title: 'Portfolio Page',
    description: 'Built with HTML and CSS in weeks 1 and 2.',
    techStack: ['HTML', 'CSS'],
    url: '',
  },
  {
    id: 2,
    title: 'React Portfolio',
    description: 'Rebuilt as a React application in weeks 4 and 5.',
    techStack: ['React', 'TypeScript'],
    url: '',
  },
  // your other projects
];

Requirements:

<aside> 💡

To collect unique tech tags from all projects: const allTags = [...new Set(projects.flatMap((p) => p.techStack))]

</aside>

4. Verify and commit

npm run dev     # no console errors or warnings
npm run build   # production build passes

Confirm all three features work together:

Push to your portfolio GitHub repository. If you're on a branch from week 4, merge it or continue on the same branch.

Hints


Submission

Follow the Assignment submission guide to learn how to submit the assignment


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.