Read here. Code on desktop. The coding workspace opens on screens 1024px and wider.
User interface challenge
Like Button
medium20 min
Build a Like button with liked, unliked, pending, and recoverable error states. Use the supplied asynchronous practice service and keep its visual state consistent with the last successful request.
Requirements
Initially show Like, aria-pressed="false", and no error. Render a native button with data-testid="like".
Clicking requests the opposite state through the supplied createLikeService() function. While its 200ms promise is pending, show Updating…, set aria-busy="true", and disable the button. Ignore duplicate requests.
Only commit the returned liked state after success. Show Liked with aria-pressed="true" when liked and Like with aria-pressed="false" otherwise.
The practice service intentionally rejects its third request. Keep the previous liked state, show its message in role="alert" with data-testid="error", and enable the button so the user can retry. Clear the error when retrying.
Create one service per mounted component; do not recreate it on each render. Avoid state updates after component destruction.
The starter supplies the semantic button and complete state-based styles. No real API, persistence, counter, or authentication is required.
Examples
Example 1
Input: Click Like and wait for the request.
Output: Liked; the control becomes available again.
The same visible behavior applies to every supported framework.