iframe puts another document in yours
An <iframe> loads a complete, separate page inside a rectangle. It has its own document, its own scripts and — if it comes from another origin — its own origin, which the browser keeps sealed off from yours.
That isolation is the point. It is also why an iframe is the right tool for running code you do not control, which is exactly what the practice labs on this site do.
<iframe src="https://example.com/map"
title="Map of the showroom"
width="800" height="450"
loading="lazy"
referrerpolicy="no-referrer"
sandbox="allow-scripts allow-same-origin"
allow="fullscreen">
</iframe>
The attributes that matter
| Attribute | Why |
|---|---|
title | Required in practice: it is the accessible name. Without it a screen reader says only "frame". |
sandbox | Removes every capability, then adds back only what you list. |
allow | Permissions policy: camera, microphone, geolocation, fullscreen, autoplay. |
loading="lazy" | Do not load it until it is near the viewport. A third-party embed is usually the heaviest thing on a page. |
referrerpolicy | How much of your URL is sent to the other site. |
width / height | Reserve the space, as with an image. |
sandbox is a deny list turned inside out
sandbox with no value removes everything: scripts, forms, popups, the origin, top-level navigation. Each token you add gives one capability back.
allow-scripts— JavaScript may run.allow-forms— forms may be submitted.allow-popups— may open a window.allow-modals— may callalertandconfirm.allow-same-origin— keeps its real origin, so it can use cookies and storage, and its DOM can be read by a same-origin parent.allow-top-navigation— may navigate your page. Almost never give this.
A same-origin frame that can run scripts can simply remove its own sandbox attribute and reload itself. For untrusted code, grant allow-scripts alone — the frame then has an opaque origin and cannot reach anything of yours.
Talking to a frame
Across origins you cannot read the other document. The only channel is postMessage, and both sides must check who they are talking to.
const frame = document.querySelector("iframe");
frame.contentWindow.postMessage({ type: "theme", value: "dark" }, "https://example.com");
addEventListener("message", (e) => {
if (e.source !== frame.contentWindow) return; // not from our frame
if (e.origin !== "https://example.com") return; // not from who we expect
console.log(e.data);
});
Never trust a message without checking origin — any page can post to any window it has a reference to.
SVG: three ways to use it
currentColormakes the icon inherit the colour of its surroundings — one file, every theme.aria-hidden="true"on a decorative icon, so it is not announced twice next to a label.focusable="false"matters for old Edge, which put SVGs in the tab order.- An SVG that carries meaning on its own needs
role="img"and a<title>as its first child.
<button class="close" aria-label="Close">
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</button>
| How | Styleable | Cached | Use for |
|---|---|---|---|
<img src="x.svg"> | No | Yes | Illustrations you do not need to restyle. |
Inline <svg>…</svg> | Yes | No (part of the HTML) | Icons that must take the text colour, and anything animated. |
CSS background-image | No | Yes | Decoration. |
SVG is markup
Inside an inline SVG you are still writing elements with attributes, and CSS can select them. That is what makes SVG the natural choice for diagrams whose parts have to change.
<svg viewBox="0 0 120 60" class="plan" role="img">
<title>Door swing in a 120 by 60 opening</title>
<rect x="0" y="0" width="120" height="60" fill="none" stroke="currentColor"/>
<path class="leaf" d="M10 50 L10 10" stroke="currentColor" stroke-width="3"/>
<path class="arc" d="M10 10 A40 40 0 0 1 50 50" fill="none" stroke-dasharray="4 4"/>
</svg>
canvas
<canvas> is a bitmap you draw on with JavaScript. It has no DOM inside it, so nothing you draw is selectable, searchable or readable by a screen reader — whatever the canvas shows must also exist as text somewhere, or be described in the fallback content between the tags.
Reach for canvas when there are thousands of things to draw or a per-pixel effect. For a chart with a dozen bars, SVG is easier and accessible by default.
<canvas id="chart" width="600" height="300" role="img"
aria-label="Lead times: painted 5 days, veneer 10 days">
<table>…the same numbers as a table…</table>
</canvas>
object and embed
Both are older, more general ways of embedding external content. In practice: use <iframe> for pages, <img> or inline markup for SVG, <video> and <audio> for media. <object> still has one use — embedding a PDF with fallback content — and <embed> has none you need.