Image wells
An image well is an editable version of an image view.
When to use it
Use an image well where people can drop in or replace a picture, like an avatar or artwork slot. For display-only images, use a plain <img>.
Preview
The first two are filled wells (30px and a scaled 64px). The third is empty. The last is disabled.
Anatomy
The well is a 30px box with a 3px radius holding a 24px image at a 3px inset; the image keeps square corners. The margin around the image fills with rgba(0, 0, 0, 0.02). The frame runs outside to in: a 0.5px soft edge at rgba(0, 0, 0, 0.05) just outside the box, a 1px white ring at the box edge, and a thin soft inner edge at 5% black under it. The white ring between dark hairlines is what makes it read as an inset well rather than a card.
Only the 30px size is canonical, but the frame is size independent: set any width and height and the inset and rings hold.
| Class | Role |
|---|---|
.p-imagewell | The well. A <label> wrapping an <img> and a hidden <input type="file">. |
.p-dragover | Drop-target highlight; add it from your drag handlers. |
.p-dimmed | Disabled look; automatic when the input is disabled. |
Behavior
The label makes the whole well activate the file picker, and the input stays keyboard focusable. Reading the chosen file into the <img> is app logic:
<label class="p-imagewell">
<img src="avatar.png" alt="Profile picture" />
<input type="file" accept="image/*" aria-label="Change profile picture" />
</label>
<script>
document.querySelector('.p-imagewell input').addEventListener('change', (e) => {
const [file] = e.target.files;
if (file) e.target.closest('.p-imagewell').querySelector('img').src =
URL.createObjectURL(file);
});
</script>
For drag and drop, toggle .p-dragover on dragenter and dragleave and read event.dataTransfer.files on drop.
States
Focus and drag-over show a 3.5px ring in the focus band color, rgba(0,136,255,0.5), with a 1px offset. Disabled (or .p-dimmed) drops the well to 50% opacity, the standard macOS dimmed treatment.
Dark mode
The well fill lifts to rgba(255, 255, 255, 0.04), the white ring drops to rgba(255, 255, 255, 0.15), and the soft edges deepen to 30% black. Both .p-dark-mode and .p-auto-dark-mode are supported.