React Progress Bar Component Challenge
Create a reusable and accessible progress bar component in React using TypeScript. This component is a fundamental UI element used to visualize the completion status of a task or process, providing immediate feedback to the user.
Problem Description
Your task is to build a ProgressBar React component that accepts a value prop representing the current progress (e.g., 50 for 50%) and an optional max prop (defaulting to 100) representing the maximum possible value. The component should visually display this progress.
Key Requirements:
- Props:
value: Anumberrepresenting the current progress. This should be a non-negative number.max(optional): Anumberrepresenting the maximum possible value. Defaults to 100. Must be a positive number.
- Visual Representation:
- The progress bar should have a container element and an inner element that fills up based on the
valueandmaxprops. - The width of the inner element should be dynamically calculated as
(value / max) * 100%.
- The progress bar should have a container element and an inner element that fills up based on the
- Accessibility:
- Implement ARIA attributes to ensure the progress bar is understandable by assistive technologies. Specifically, use
role="progressbar",aria-valuenow,aria-valuemin, andaria-valuemax.
- Implement ARIA attributes to ensure the progress bar is understandable by assistive technologies. Specifically, use
- Styling:
- The component should be stylable via CSS. You can assume basic styling will be provided or implement minimal inline styles for demonstration.
- TypeScript:
- All component props and internal logic should be typed using TypeScript.
Expected Behavior:
- When
valueis 0, the progress bar should appear empty. - When
valueequalsmax, the progress bar should appear full. - When
valueis between 0 andmax, the progress bar should be partially filled proportionally. - The component should gracefully handle edge cases like
valueexceedingmaxorvaluebeing negative.
Edge Cases:
valueis negative.valueis greater thanmax.maxis 0 or negative.valueormaxare not integers.
Examples
Example 1: Basic Usage
// Assume ProgressBar is imported and used like this:
<ProgressBar value={75} />
Output:
A visual progress bar filled to 75% of its width.
Explanation: max defaults to 100. The inner bar's width is calculated as (75 / 100) * 100% = 75%. ARIA attributes would be set as aria-valuenow={75}, aria-valuemin={0}, aria-valuemax={100}.
Example 2: Custom Max Value
// Assume ProgressBar is imported and used like this:
<ProgressBar value={30} max={50} />
Output:
A visual progress bar filled to 60% of its width.
Explanation: max is explicitly set to 50. The inner bar's width is calculated as (30 / 50) * 100% = 60%. ARIA attributes would be set as aria-valuenow={30}, aria-valuemin={0}, aria-valuemax={50}.
Example 3: Edge Case - Value Exceeding Max
// Assume ProgressBar is imported and used like this:
<ProgressBar value={120} max={100} />
Output:
A visual progress bar filled to 100% of its width (capped at max).
Explanation: Although value (120) is greater than max (100), the progress bar should visually represent 100% completion. The calculated width will be capped at 100%. ARIA attributes would reflect the actual value: aria-valuenow={120}, aria-valuemin={0}, aria-valuemax={100}.
Example 4: Edge Case - Negative Value
// Assume ProgressBar is imported and used like this:
<ProgressBar value={-10} max={100} />
Output:
A visual progress bar that appears empty (0% filled).
Explanation: A negative value should be treated as 0 for visual representation. The inner bar's width will be 0%. ARIA attributes would reflect the capped value: aria-valuenow={0}, aria-valuemin={0}, aria-valuemax={100}.
Constraints
- The
valueprop must be anumber. If a negative value is provided, it should be visually clamped to 0. Ifvalueexceedsmax, it should be visually clamped tomax. - The
maxprop, if provided, must be a positivenumber. Ifmaxis not a positive number (e.g., 0 or negative), the component should default to a sensible maximum (e.g., 100) or handle this gracefully. For this challenge, assumemaxwill be a positive number if provided, or default to 100. - The component should render without errors and provide a functional progress bar for valid inputs.
- Performance is not a primary concern for this specific challenge, but avoid unnecessary re-renders.
Notes
- Consider how you will handle the dynamic width calculation. You can use inline styles or CSS classes.
- Think about the semantic meaning of ARIA attributes and how they convey information to users of screen readers.
- You might want to add a visual indicator for the percentage text, though this is not strictly required for the core functionality.
- For accessibility, ensure the contrast ratio between the filled and unfilled parts of the bar is sufficient.