Welcome back! In the previous lesson, you learned how to set up a consistent layout and client-side routing for your React app. Now that you have a solid structure, it’s time to focus on the building blocks of your user interface: foundational UI components.
Foundational UI components are small, reusable pieces of your app’s interface. They help you keep your code organized, make your app look consistent, and save you time when building new features. In this lesson, you will learn how to create three common UI components: a loading spinner, a search input, and a pagination control. These components are used in many real-world applications, and you will see how to build and use them in your own projects.
Let’s start by creating a Spinner component. A spinner is a small animation that shows users something is loading. This is helpful when you are waiting for data from a server or when an action takes a moment to complete.
Here is the code for a simple Spinner component:
Explanation:
- The
Spinnerfunction returns adivcontaining an SVG. The SVG is styled to spin, creating a loading animation. - The
aria-label="Loading"attribute helps screen readers understand what this element means, making your app more accessible. - The
classNamevalues use Tailwind CSS utility classes for styling and animation. On CodeSignal, Tailwind is pre-installed, so you do not need to set it up yourself.
Output:
When you use <Spinner /> in your app, you will see a spinning blue circle, indicating that something is loading.
The outer div uses flex, justify-center, and to the spinner, while the padding prevents the SVG from feeling cramped; the spins because Tailwind’s applies a keyframed , and the color comes from , which sets so both the with and the wedge with share the same hue; the visual effect of a “missing slice” comes from rendering a ( stroke) behind a ( fill), which makes the rotation obvious without extra images or GIFs, and the accessible label (“Loading”) lets tests target it with queries like while remaining visually minimal.
Next, let’s build a SearchInput component. Search inputs are common in apps where users need to find information quickly. This component will include a search icon and be accessible to all users.
Here is the code for the SearchInput component:
Explanation:
- The component accepts all standard input props, so you can use it just like a regular input.
- The search icon is placed inside the input using absolute positioning.
- The input is styled for a modern look and is accessible with proper focus and ARIA attributes.
Output:
When you use <SearchInput placeholder="Search..." />, you will see a search box with a search icon on the left.
Typing the props as InputHTMLAttributes<HTMLInputElement> means consumers can pass any standard input attribute (e.g., value, onChange, name, aria-*) without redefining them, and because the component on the specifying its own attributes, a consumer-provided or will the defaults; the wrapper is so the icon’s container can be with and to vertically center the SVG, and the input’s reserves space so the text doesn’t overlap the icon; the SVG has because it’s purely decorative, while the input gains its accessible name from whatever the caller provides (e.g., in the demo), and ensures a clear focus outline for keyboard users.
Pagination helps users move through large sets of data, such as lists or tables. Let’s create a simple Pagination component with "Previous" and "Next" buttons.
Here is the code for the Pagination component:
Explanation:
- The component takes the current page, the total number of pages, and a function to handle page changes.
- The "Previous" button is disabled on the first page, and the "Next" button is disabled on the last page.
- The current page number is shown in the middle, styled to stand out.
The local prev and next handlers compute a target page and immediately call onChange with that number, using Math.max(1, page - 1) and Math.min(totalPages, page + 1) to clamp the value so it never falls outside [1, totalPages]; the nav element with gives screen readers a clear region name, the disabled state is derived purely from the and props (so a state update in the parent automatically updates button interactivity), and wiring it as works because the React state setter expects a when updating a numeric state—matching the component’s callback shape exactly.
Now, let’s see how these components work together on a single page. Here is a demo page that uses all three components:
Explanation:
- The page uses React’s
useStateto manage the search query, loading state, and current page. - When the "Search" button is clicked, the spinner appears for a short time to simulate loading.
- The search input, spinner, and pagination are all displayed together, showing how these components can be reused and combined.
The fakeSearch function is intentionally simple: it sets isLoading to true immediately, then schedules a setIsLoading(false) call after using . This introduces a that mimics the waiting period you would normally experience when making an API request. The purpose here is not to actually fetch data but to —you get to see the spinner appear, remain visible for a moment, and then disappear when the "request" completes. This is valuable because it confirms the spinner correctly responds to changes in state, demonstrates how a loading indicator improves user experience during waits, and prepares you to later replace the mock delay with a real asynchronous fetch. By using a predictable timeout instead of a real network call, the demo stays deterministic and easy to test without external dependencies.
In this lesson, you learned how to build three foundational UI components: a loading spinner, a search input, and a pagination control. You also saw how to combine them on a single page to create a smooth and interactive user experience.
These components are the building blocks for many features in modern web apps. In the next set of practice exercises, you will get hands-on experience using and customizing these components. This will help you become more comfortable building your own reusable UI elements in React. Good luck, and have fun practicing!
