The <canvas> element is a blank rectangle that you draw on with JavaScript, pixel by pixel. It's how browser games, drawing apps, charts, image editors, photo filters and many data visualisations are made. On its own, a canvas shows nothing; all the drawing happens in a script.
You draw through a context, an object full of drawing commands. The common one is the 2D context: canvas.getContext('2d'). It can fill and outline rectangles, draw lines and curves, write text, paint images and apply colours, gradients and shadows. Coordinates start at the top-left corner at (0, 0), with x increasing to the right and y increasing downwards.
Canvas is very fast for drawing lots of things, but what you draw becomes plain pixels: there are no elements to click or style afterwards, and screen readers can't see the drawing. In this lesson you'll learn the drawing basics, how to make a canvas sharp on high-resolution screens, and when SVG is the better choice.
Getting started
<canvas id="art" width="300" height="150">A drawing of a red square.</canvas>
<script>
const canvas = document.getElementById('art');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'crimson';
ctx.fillRect(20, 20, 100, 60); // x, y, width, height
</script>- The
widthandheightattributes set the drawing size in pixels; the default is 300 by 150. - Text between the tags is fallback content for browsers and screen readers that can't show the canvas. Describe what's drawn.
- Set colours with
fillStyle(inside) andstrokeStyle(outline) before drawing.
Drawing commands
| Command | Draws |
|---|---|
fillRect(x, y, w, h) / strokeRect(...) | Filled or outlined rectangle |
clearRect(x, y, w, h) | Erases an area |
beginPath(), moveTo(x, y), lineTo(x, y), stroke() | Lines and shapes |
arc(x, y, r, start, end) then fill() | Circles and arcs (angles in radians, a full circle is Math.PI * 2) |
fillText(text, x, y) | Text, styled with ctx.font |
drawImage(img, x, y, w, h) | An image, once it has loaded |
createLinearGradient(...) | A gradient to use as a fill |
lineWidth sets the thickness of strokes, and ctx.globalAlpha sets transparency for everything drawn afterwards.
Sharp and responsive canvases
On high-resolution screens a 300 by 150 canvas can look blurry, because each canvas pixel is stretched over several screen pixels. The fix is to draw at a larger size and scale back down:
const ratio = window.devicePixelRatio || 1;
canvas.width = 300 * ratio;
canvas.height = 150 * ratio;
canvas.style.width = '300px';
ctx.scale(ratio, ratio);For responsive layouts, set the CSS width to 100% and redraw when the size changes. Remember that changing canvas.width clears the drawing.
HTML Canvas Syntax
Canvas syntax
<canvas id="c" width="400" height="200">Description of the drawing</canvas>
<script>
const ctx = document.getElementById('c').getContext('2d');
ctx.fillStyle = '#2563eb';
ctx.fillRect(10, 10, 80, 50);
ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(200, 100); ctx.stroke();
ctx.beginPath(); ctx.arc(300, 60, 40, 0, Math.PI * 2); ctx.fill();
ctx.font = '20px sans-serif'; ctx.fillText('Hello', 10, 160);
</script>HTML Canvas Summary
<canvas>is a drawing surface; JavaScript draws on it throughgetContext('2d').- Coordinates start at the top-left, with y increasing downwards.
- Use fillRect, paths with moveTo and lineTo, arc, fillText and drawImage to draw.
- Add fallback text inside the element to describe the drawing.
- Scale by devicePixelRatio for sharp results; use SVG when you need scalable, accessible shapes.
HTML Canvas Examples
Each example runs in the page. Edit the code and press Run to see what changes.
Shapes, lines and text
<canvas id="scene" width="320" height="180" style="border: 1px solid #ddd">A sunny scene with a house and the word Home.</canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
ctx.fillStyle = '#bfdbfe';
ctx.fillRect(0, 0, 320, 180);
ctx.fillStyle = '#fbbf24';
ctx.beginPath();
ctx.arc(270, 40, 24, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#f97316';
ctx.fillRect(110, 90, 100, 70);
ctx.beginPath();
ctx.moveTo(100, 90);
ctx.lineTo(160, 45);
ctx.lineTo(220, 90);
ctx.closePath();
ctx.fillStyle = '#7c2d12';
ctx.fill();
ctx.fillStyle = '#1f2937';
ctx.font = 'bold 18px sans-serif';
ctx.fillText('Home', 135, 135);
</script>Line-by-line explanation
- Line 1The fallback text describes the picture.
- Lines 4 to 5A sky-blue background over the whole canvas.
- Lines 7 to 9A sun drawn as a full circle.
- Line 11The walls of the house.
- Lines 12 to 18A triangular roof made from a path.
- Lines 20 to 21Text needs a font before it's drawn.
A simple bar chart
<canvas id="chart" width="320" height="200">Bar chart of sales: Mon 12, Tue 19, Wed 7, Thu 15, Fri 22.</canvas>
<script>
const data = { Mon: 12, Tue: 19, Wed: 7, Thu: 15, Fri: 22 };
const ctx = document.getElementById('chart').getContext('2d');
const max = Math.max(...Object.values(data));
ctx.font = '12px sans-serif';
Object.entries(data).forEach(([day, value], i) => {
const h = (value / max) * 150;
const x = 20 + i * 60;
ctx.fillStyle = '#16a34a';
ctx.fillRect(x, 170 - h, 40, h);
ctx.fillStyle = '#111827';
ctx.fillText(day, x + 8, 188);
ctx.fillText(value, x + 12, 165 - h);
});
</script>Line-by-line explanation
- Line 1The fallback lists every value, so the chart's data is accessible.
- Line 5The largest value decides the scale.
- Line 8Each bar's height is proportional to its value.
- Line 11Bars are drawn upwards from a baseline at y = 170.
- Lines 13 to 14Labels for the day and the value.
A gradient and an image
<canvas id="card" width="300" height="160">A greeting card with a sunset gradient and a small photo.</canvas>
<script>
const ctx = document.getElementById('card').getContext('2d');
const g = ctx.createLinearGradient(0, 0, 0, 160);
g.addColorStop(0, '#f97316');
g.addColorStop(1, '#7c3aed');
ctx.fillStyle = g;
ctx.fillRect(0, 0, 300, 160);
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => ctx.drawImage(img, 190, 30, 90, 90);
img.src = 'https://picsum.photos/seed/canvas/90/90';
ctx.fillStyle = 'white';
ctx.font = 'bold 22px sans-serif';
ctx.fillText('Good evening', 16, 85);
</script>Line-by-line explanation
- Lines 4 to 6A vertical gradient from orange to purple.
- Lines 7 to 8The gradient is used as the fill.
- Lines 9 to 12An image can only be drawn after it has loaded.
- Lines 13 to 15White text on top of the gradient.
Common HTML Canvas Mistakes
Sizing a canvas only with CSS
<canvas id="c" style="width: 600px; height: 300px"></canvas> <!-- drawn at 300 by 150, then stretched --><canvas id="c" width="600" height="300"></canvas>CSS stretches the default 300 by 150 drawing, making it blurry and distorted.
Drawing an image before it loads
<script>
const img = new Image(); img.src = 'photo.jpg';
ctx.drawImage(img, 0, 0); // nothing appears
</script><script>
const img = new Image();
img.onload = () => ctx.drawImage(img, 0, 0);
img.src = 'photo.jpg';
</script>Canvas with no fallback text
<canvas id="chart"></canvas><canvas id="chart">Sales rose from 12 orders on Monday to 22 on Friday.</canvas>Screen readers can't see what's drawn, so describe it.
HTML Canvas in Real Projects
Canvas in the wild
Browser games, online whiteboards like Excalidraw, chart libraries such as Chart.js, photo editors, signature pads on delivery apps, and image compression tools all draw on canvas. Larger 3D experiences use the same element with the WebGL context instead of 2D.
HTML Canvas Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Get the 2D drawing context.
<script>
const ctx = canvas.('2d');
</script>
Where is the point (0, 0) on a canvas?
What does arc(50, 50, 20, 0, Math.PI * 2) describe?
When is SVG usually better than canvas?
Nothing is drawn: the context is requested with the wrong name and the colour is set after drawing. Fix it so the square is green.
<canvas id="c" width="120" height="120">A green square</canvas>
<script>
const ctx = document.getElementById('c').getContext('two-d');
ctx.fillRect(10, 10, 100, 100);
ctx.fillStyle = 'green';
</script>- The centre pixel is green
- No errors
HTML Canvas Quiz
5 questions to check what you learned.
What draws on a canvas?
- JavaScript
- CSS
- HTML attributes
- The browser automatically
What do the width and height attributes of canvas control?
- The number of drawing pixels
- Only the visible size
- The border
- The zoom level
Which method writes text on a canvas?
- drawText
- writeText
- text
- fillText
Why do canvases look blurry on high-resolution screens?
- Canvas doesn't support colour
- Browsers compress them
- Each canvas pixel is stretched over several screen pixels
- The fallback text overlaps
Why is canvas content not accessible by default?
- It's always hidden
- It's just pixels, with no elements or text that assistive technology can read
- It requires a plug-in
- Canvas can't be used with keyboards
HTML Canvas Challenge
Draw a flag
Draw on a canvas with id="flag", 240 by 160:
- Fill the whole canvas with blue (
#1d4ed8) - Draw a white rectangle across the middle
- Include fallback text inside the canvas element
- Canvas is 240 by 160
- Top-left area is blue
- Middle is white
- Has fallback text