October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk3 min

Create a Reusable Button Component in React

Create a small reusable React button with a native element, purposeful variants, forwarded attributes, accessible naming, and clear guidance on disabled and pending states.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build reusable React buttons around a native <button>, a small set of purposeful props, and the native attributes your app already expects. Use buttons for actions and links for navigation; give icon-only controls an accessible name and keep keyboard focus visible.

Build a small native button component

React components let you combine interface elements into reusable, nestable components and configure them with props, as the React documentation explains. The prop names and visual variants below are design choices, not requirements imposed by React.

import type { ButtonHTMLAttributes } from 'react';

type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
  variant?: 'primary' | 'secondary';
};

export function Button({
  variant = 'primary',
  type = 'button',
  className = '',
  ...props
}: ButtonProps) {
  return (
    <button
      type={type}
      className={`button button--${variant} ${className}`.trim()}
      {...props}
    />
  );
}

This TypeScript example accepts normal button attributes, including children, disabled, onClick, and accessibility attributes, and passes them to the native element. The default type="button" prevents an ordinary control from accidentally submitting a surrounding form; callers can explicitly pass type="submit" when submission is intended.

Keep variants tied to meaningful design-system roles rather than exposing every CSS property as a prop. Add another variant only when it represents a real, repeated choice in the interface. For plain JavaScript, remove the type declarations and keep the same component behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a button for actions and a link for navigation

A button performs an action in the current interface, such as saving changes or opening a dialog. Navigation to another page or location belongs on a link. React Aria documents this distinction and provides a separate Link component; sharing visual styles does not require combining both semantics in one component (React Aria Button documentation).

A component that sometimes renders a button and sometimes an anchor has to preserve different native behavior and accessibility expectations. Prefer separate Button and Link components when both are needed. Carbon’s Button documentation likewise notes that substituting a non-button element brings accessibility considerations (Carbon Button documentation).

Keep native behavior, labels, and focus intact

  • Use descriptive action text. Choose concise wording that makes the result clear, such as “Save changes,” rather than a vague label. The U.S. Web Design System recommends short, action-oriented button labels (USWDS Button guidance).
  • Name icon-only controls. If the visible content is only an icon, provide an accessible name with aria-label or aria-labelledby; the graphic alone does not explain the action.
  • Do not discard the native element’s affordances. Preserve ordinary button attributes and event handlers by forwarding them to the underlying <button>. Avoid recreating keyboard activation or focus behavior when the native element already supplies it.
  • Keep focus visible. Custom styles should retain a visible focus indicator, and the indicator and button text should be checked for contrast in the actual theme and context.
  • Use the native disabled prop when disabling. A native disabled button cannot be activated. By contrast, aria-disabled="true" communicates a state but does not itself prevent activation; application code must enforce that behavior, as USWDS notes.

For projects that want documented interaction and accessibility behavior while retaining control over DOM structure and styling, Adobe’s React Aria getting-started guide describes primitives that can be adopted incrementally. Its useButton documentation covers mouse, keyboard, touch, focus, and ARIA behavior, with the element type defaulting to a button. A native implementation keeps the dependency surface small but leaves those design and accessibility responsibilities with the application.

Add a pending state only when its behavior is defined

A spinner alone does not prevent repeated activation or announce that work is underway. If a control has a pending state, decide how it responds to activation, whether it remains focusable, and what assistive technology announces. React Aria’s Button documentation describes isPending as disabling press and hover while retaining focusability and announcing the pending state (React Aria Button documentation). A custom boolean prop does not automatically provide those behaviors; implement and verify them deliberately.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose the implementation that fits the project

Approach What it offers What your project owns
Native React component Direct control with a minimal dependency surface; built on the browser’s button behavior. The component API, styling, and any additional state or accessibility behavior.
React Aria behavior primitive Documented interaction and accessibility behavior for mouse, keyboard, and touch, while leaving DOM structure and styling to the implementer. Choosing its API and integrating the behavior into the project’s markup and styles.

Use the native component when a small, application-specific wrapper is enough and the team can maintain its interaction details. Consider React Aria when its documented behavior is valuable and its API and dependency fit the design system. Neither route is universally best: the scope of the system and the behavior it needs should drive the choice.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.