Skip to content

No.55 · Buttons· New

Avatar Upload

A round photo picker whose ring is the progress. The chosen photo shows at once, dimmed, while the ring fills around it; then a full green ring, a small pen badge and 'Photo updated', or a red ring and a plain reason with Retry.

The prompt

Copy this text

Automatic copying is unavailable. Copy the selected text using your device’s copy command.

Written for the variant you picked above: Light

Build a round profile-photo picker whose ring is the upload's progress. Inter at 500, 15px. Palette (light / dark): ink #111111 / #ededed, muted #6b6b6b / #a0a0a0, card #ffffff / #141414, hairline #e2e2e2 / #2b2b2b, dashes #c9c9c9 / #3d3d3d, solid button #111111 with white text / #ededed with #0a0a0a text, accent #2563eb / #6ea8fe with a wash of #eff4ff / #101b2e, track #ececec / #262626, done #15803d / #3fb950, error #c81e1e / #ff6369. Idle: a 96px round picker with a camera icon on a faint 84px disc inside a dashed 2.5px ring, captioned 'Add a photo' / 'JPG or PNG, up to 8 MB'; hover or a drag over it washes the disc in the accent. Images only. The chosen photo appears dimmed at once (an object URL) while the ring fills in the accent around it, clockwise from 12 o'clock, with the percentage in the middle and 'Uploading…' / 'Cancel' beside it. Done: the photo at full strength, a full green ring, a small pen badge (28px, ringed in the card colour), 'Photo updated' with a tick and 'Remove'. A refused or failed upload turns the ring red and shows the reason with Retry. Behaviour: a hidden <input type=file> opened by a real button; dropping a file on the control works too (with a visible drag state). Check the file against accept and a size limit first and say why in plain words if it's refused ('That file is 31 MB; the limit is 20 MB.'). Uploading takes an upload(file, progress, signal) function; the default simulates a believable transfer (uneven but always forward, 1.1–4.2s by size) and fails when the browser is offline. Cancel aborts it. A failure shows the reason and 'Retry', which sends the same file again. Long names are shortened in the middle, keeping the extension. Progress is announced in quarters in a polite live region, along with the start, the end, cancelling and errors. Show it centred on a #f6f6f5 / #0a0a0a page. Selected variant — Light (light): Palette for this theme (Light): --avub-accent #2563eb; --avub-bad #c81e1e; --avub-btn #111111; --avub-btn-ink #ffffff; --avub-card #ffffff; --avub-dash #c9c9c9; --avub-edge #e2e2e2; --avub-focus #2563eb; --avub-ink #111111; --avub-ok #15803d; --avub-soft #6b6b6b; --avub-track #ececec; --avub-wash #eff4ff. Treat these as the root colour tokens, one value per role, and name them to suit your code. Select it with the theme option set to "light". Keep every dimension, spacing value, state and motion from the brief unchanged, and keep text at 4.5:1 contrast or better on these surfaces. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: Click (or Enter/Space) to choose a photo, or drop one on the circle. While uploading, Cancel stops it. When done, clicking the circle changes the photo and Remove clears it; when it fails, Retry resends. Motion: The ring fills frame by frame as the transfer progresses. Reduced motion keeps the progress. Accessibility: A real button named for its state ('Add a photo', 'Uploading photo, 40 percent', 'Change photo'); the hidden input is out of the tab order; errors are text, not just colour; progress is announced in quarters. Responsive behavior: The picker keeps its 96px size with its caption beside it. Touch: Tapping opens the system photo picker; drag and drop is an extra, not a requirement. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.

Notes

Interaction
Click (or Enter/Space) to choose a photo, or drop one on the circle. While uploading, Cancel stops it. When done, clicking the circle changes the photo and Remove clears it; when it fails, Retry resends.
Motion
The ring fills frame by frame as the transfer progresses. Reduced motion keeps the progress.
Accessibility
A real button named for its state ('Add a photo', 'Uploading photo, 40 percent', 'Change photo'); the hidden input is out of the tab order; errors are text, not just colour; progress is announced in quarters.
Responsive
The picker keeps its 96px size with its caption beside it.
On touch
Tapping opens the system photo picker; drag and drop is an extra, not a requirement.

Featured

425 components