Media & avatar
Avatar upload + cropping JS
A .joy-avatar-upload needs to be a <label> wrapping a preview <img> and a hidden <input type="file">. On change, open JoyCropper before showing the result:
<label class="joy-avatar-upload">
<img src="/avatar.png" alt="">
<span class="joy-avatar-upload-icon"><i class="ph ph-camera"></i></span>
<input type="file" accept="image/*" hidden>
</label>input.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const blob = await JoyCropper.open(file, { outputSize: 512 });
if (blob) preview.src = URL.createObjectURL(blob);
});API details at JavaScript API → JoyCropper.
Camera overlay
Originally built for a facial verification flow. You write the getUserMedia() logic yourself — Joy only styles the guide frame:
| Class | Guide shape |
|---|---|
.joy-camera-overlay | default oval, for framing a face from a normal distance |
.joy-camera-overlay.is-closeup | larger oval, for asking the user to move closer |
.joy-camera-overlay.is-document | wide rectangle, for documents |
<div class="joy-camera-box">
<video autoplay playsinline></video>
<div class="joy-camera-overlay is-closeup"></div>
</div>
<button type="button" class="joy-btn-capture"><i class="ph ph-camera"></i></button>Camera access requires HTTPS and explicit user permission — handle denied permission and missing cameras in your own JS, Joy doesn't cover those cases.
News thumbnail
Used inside .joy-news-card (see Marketing blocks) — a standard <img>, no special class:
<img src="/thumbnail.jpg" alt="" class="joy-news-thumb">