Blog · · 8 min

Add to cart button

An add to cart button names what is being added and carries the total whenever the selection above it can change the price: `Add 3 tins · $48.00`. It needs one pending state, one confirmation announced to assistive technology, a tap target of 44 CSS pixels, and no second button of equal weight beside it.

By

The button says what is going into the cart. Add 3 tins · $48.00, not Add to cart, whenever anything above it can change what the buyer gets or what it costs. On a page with one price and one variant, Add to cart is complete and the total in the label is noise. That single decision (does the selection above this button move?) settles the label, and most of the rest follows from it.

One oversized machined brass push button with a knurled rim, seated in a milled recess in a slab of dark slate, raking light from the left along its bevel and a black shadow gap under the right edge.
One control, given the whole surface. That is the arrangement the page is arguing about when it asks whether Buy now belongs next to it.

What the label has to carry

Three inputs, in this order of importance.

The verb and the object. Add alone tells the buyer nothing about what they picked, which matters on any page where more than one thing is pickable. Add 3 tins closes the loop between the tier they tapped and the action they are about to take.

The total, conditionally. Put the money in the button when the price on that screen is a function of a control on that screen. A quantity stepper, a tier selector, a size that changes price, a bundle toggle. In all four cases the button is the receipt for a calculation the buyer just made, and reading it back is what stops them scrolling up to check. On a fixed-price page, leave the money where it already is.

Nothing else. No Free shipping, no In stock, no countdown. Those are separate claims with separate consequences, and one of them has a legal shape of its own.

A worked version of the rule:

PageCan the price move on screen?Label
Single SKU, one pricenoAdd to cart
Quantity stepperyesAdd 2 · $38.00
Three-tier selectoryesAdd 3 tins · $48.00
Size changes priceyesAdd 90 ml · €129.00
Subscription toggleyesSubscribe · $17.10 / month

The three states, and the one that gets skipped

Idle. The label above.

Pending. The button stays at the same width. A label that shrinks from Add 3 tins · $48.00 to Adding… makes the whole block reflow under the buyer's thumb at the exact moment they are watching it. Reserve the width, swap the inner content, and keep the accessible name stable or update it deliberately with aria-busy.

Confirmed. This is the state almost every generated implementation drops. Something has to say the item arrived, and it has to say it to a screen reader as well as to the eye. One polite live region does both:

<button onClick={add} aria-busy={pending} disabled={pending}>
  {pending ? "Adding…" : `Add ${qty} tins · ${money(total)}`}
</button>
<p aria-live="polite" className="sr-only">{annonce}</p>
// annonce = "3 tins added. Cart total $48.00."

Opening a drawer counts as confirmation for a sighted buyer and counts as nothing at all for someone who cannot see it move. The live region is one line and it is the difference between a component that works and a component that looks like it works.

Colour is the question everyone asks

It is also the one with the least in it. We pulled United States Google volumes for this cluster on 31 August 2026:

QueryMonthly searches
add to cart button880
black add to cart button590
green add to cart button390
add to cart button animation320
add to cart button with quantity140
sticky add to cart button110
add to cart button css90
add to cart button color20

Almost as many people want a specific colour as want the button itself, and the two colours they want are opposites. That is the tell. No hue wins, because the variable is not hue. It is whether the button is the highest-contrast element in its region, and whether nothing else on the page shares that treatment.

Two figures are actually specified rather than argued about. WCAG 2.1 success criterion 1.4.3 asks for a contrast ratio of at least 4.5:1 between the label and the button fill for normal-sized text. Criterion 1.4.11 asks for 3:1 between the button and whatever it sits on, so a pale button on a pale card fails even when its own label passes. Measure both. Then stop reading colour psychology.

Size, and the numbers that are written down

WCAG 2.2 added success criterion 2.5.8, Target Size (Minimum), at Level AA. It asks for at least 24 by 24 CSS pixels, with exceptions for spacing and for inline targets. The older 2.5.5 sits at Level AAA and asks for 44 by 44. Apple's Human Interface Guidelines have long recommended 44 by 44 points, and Material Design asks for 48 by 48 density-independent pixels.

Take 44. A primary purchase control that only clears the AA floor is a control designed to the legal minimum, and the AA floor exists to catch small inline links rather than to size the one button the page was built around. On mobile, full bleed inside the content gutter, with the bottom safe area respected once the same button becomes sticky.

Add to cart beside Buy now

Two buttons of equal weight are two decisions. The buyer wanted to make one.

If the page needs an express path, make it visually secondary and put it second in the DOM, so the primary action is also the first thing a keyboard reaches. Where the express path is a wallet button rendered by a payment provider, its styling is often outside your control, which is an argument for keeping your own button plainly dominant rather than for matching it.

One more constraint applies in Europe and it is the kind an agent will not invent. Under Article 22 of Directive 2011/83/EU, any extra payment on top of the main contract needs the consumer's express consent, and consent inferred from a default option does not count. So a pre-ticked warranty, gift wrap or complement sitting above the button is unlawful there, whatever it does to the average order. The same rule shapes where a complement can legally sit.

What an agent writes when nothing tells it otherwise

Ask a coding agent for an add-to-cart button and you reliably get a rounded rectangle with a gradient, the literal string Add to Cart, a disabled attribute wired to a loading boolean, and no live region. Every one of those is the median of what has been published. The label is generic because most published examples are catalogue demos where nothing above the button can move, and the confirmation is missing because a demo has nothing to confirm.

The fix is not a better prompt. It is handing the agent a component whose props make the wrong version impossible to write, which is the same argument as the tier selector spec and the reason general registries stop short of these four blocks.

<AddToCart
  items={[{ sku: "tin-guji", qty: 3 }]}
  totalCents={4800}
  currency="USD"
  onAdded={openDrawer}
/>
// → "Add 3 tins · $48.00", pending state, live confirmation

No label prop. The label is derived, so it cannot drift from the selection it describes.

Disclosure. We build uxgen, an MCP server that hands a coding agent this component and the rest of the basket set. They are shown running here, and the plans are on the pricing section.

FAQ

What should an add to cart button say?

It should name what is being added, and carry the total whenever a control on the same screen can change the price. Add 3 tins · $48.00. On a page with one fixed price and one variant, Add to cart is complete and adding the total repeats what is already on screen.

Does the colour of the add to cart button matter?

Contrast matters, hue does not. Search demand splits almost evenly between black and green, which is the evidence that no colour wins. Aim for 4.5:1 between the label and the fill and 3:1 between the button and its background, then make sure nothing else on the page shares that treatment.

How big should an add to cart button be?

At least 44 by 44 CSS pixels. WCAG 2.2 sets a floor of 24 by 24 at Level AA and 44 by 44 at Level AAA, and both Apple and Material recommend 44 or 48. The AA floor is meant for small inline targets rather than for the page's primary purchase control.

Should Add to cart and Buy now sit side by side?

Only if one of them is clearly secondary. Two controls of the same visual weight turn one decision into two. Keep the add-to-cart button dominant, place the express path after it in the DOM, and never pre-tick a paid extra above either of them, which Article 22 of the EU Consumer Rights Directive prohibits.

uxgen is a service of UXGen AI, LLC — 131 Continental Dr, Suite 305, Newark, DE 19713, United States.

© 2026 UXGen AI, LLC. All rights reserved.