Skip to content

vivian-mca/interactive-rating-component

Repository files navigation

desktop design

Interactive Rating Component

Solution for a challenge from frontendmentor.io.

Table of contents

Overview

About

Users should be able to:

  1. Select and submit a number rating
  2. See the "Thank you" card state after submitting a rating
  3. See hover and focus states for all interactive elements on the page

Screenshot

Mobile design

mobile design


Active state

active state


"Thank You" card state

active state


My process

Built with

  • React.js
  • React Hooks (useState, useEffect, and custom useMediaQuery)
  • CSS Modules
  • CSS Custom Properties
  • CUBE CSS methodology
  • CSS Flexbox & Grid
  • Mobile-first workflow
  • Netlify for deployment

What I learned

This project was a full deep dive into structuring a React component-based application while implementing best practices for state management, hooks, and styling methodologies. Here are my few key takeaways:

1. Managing Back Navigation in React

One of the first things I noticed was that clicking the back button didn’t return to the rating card. My instinct was to navigate back, so I implemented a solution using the popstate event to handle browser history changes.

// Listen for browser back button
useEffect(() => {
  const handlePopState = () => {
    setIsSubmitted(false); // Reset submission state
    setSelectedRating(null); // Reset rating selection
  };

  window.addEventListener("popstate", handlePopState);
  return () => window.removeEventListener("popstate", handlePopState);
}, []);

This ensures that when users click the back button, the app resets correctly instead of getting stuck in a submitted state.

2. Using a Custom Hook (useMediaQuery)

For the desktop version, I needed to adjust the card size dynamically. I implemented a custom React Hook (useMediaQuery) to check screen width and conditionally apply different class names for styling.

function useMediaQuery(query) {
  // Tracks whether the media query matches or not
  const [matches, setMatches] = useState(() => {
    return window.matchMedia(query).matches; // Initialize state based on current match status
  });

  useEffect(() => {
    const mediaQueryList = window.matchMedia(query); // Create a media query list object
    const updateMatch = (event) => setMatches(event.matches); // Update state when the media query match status changes

    mediaQueryList.addEventListener("change", updateMatch); // Attach the event listener
    return () => {
      mediaQueryList.removeEventListener("change", updateMatch); // Cleanup function to remove the event listener when the component unmounts
    };
  }, [query]); // Runs only when the query changes

  return matches; // Return the boolean value indicating if the query matches
}

This allowed me to swap out class names dynamically, especially since I use CSS utility classes, ensuring a smooth transition between mobile and desktop layouts.

3. Structuring a Component-Based UI

I focused on keeping my React components modular and reusable, breaking them down into:

  • Card.jsx – Main rating card
  • RatingButton.jsx – Individual rating buttons
  • RatingGroup.jsx – Group of rating buttons
  • SubmitButton.jsx – Submission button
  • ThankYouCard.jsx – Thank you message

This structure helped separate concerns, making it easier to manage state and styles independently.

Continued development

Moving forward, I want to:

  • Explore React Context API for managing state globally.
  • Improve handling of accessibility (ARIA labels, focus states, screen reader support).
  • Continue refining my CSS architecture by balancing utilities with component-scoped styles.

I struggled with props management during this project, so I want to hone my skills more in creating React apps and deep dive into other useful hooks that are common in the industry.

Getting started

Installation & Setup

To run this project locally, follow these steps:

  1. Clone the repository
git clone https://github.com/vivian-mca/interactive-rating-component.git
cd your-repo-name
  1. Install dependencies
npm install
  1. Run the development server
npm run dev

This will start the project on http://localhost:5173/ (or another available port if 5173 is in use).

  1. Build for production If you want to create an optimized production build:
npm run build
  1. Preview the production build
npm run preview

This will serve the built project locally for testing.

Deployment

This project is deployed using Netlify. If you want to deploy your own version:

  1. Push your code to GitHub (or any Git provider).
  2. Connect the repository to Netlify.
  3. Set the build command:
npm run build
  1. Set the publish directory:
dist
  1. Deploy and share your live project!

Useful resources

  • React Docs - They really have great documentation on everything React.
  • CSS Logical Properties and Values - This is a good resource for learning about CSS Logical Properties and Values.
  • CUBE CSS documentation - From the docs: "CUBE CSS is a CSS methodology that’s orientated towards simplicity, pragmatism and consistency. It’s designed to work with the medium that you’re working in—often the browser—rather than against it."
  • Every Layout - Extremely helpful resource for simplifying CSS layouts.
  • Figma - Really helpful for extracting information about measurements
  • Modern CSS Reset
  • Perfect Pixel - Awesome Chrome extension that helps you to match the pixels of the provided design.
  • Responsively App - This DevTool helps in responsive web development. It allows you to see mirrored user-interactions across all devices. I find it helpful in finding breaking points and making sure my app is responsive.

Author

Acknowledgments

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published