Canvas Shadows

shadowColor, shadowBlur, and the shadowOffset properties let Canvas cast soft drop shadows behind any shape, text, or image.

How Canvas Shadows Work

Canvas can automatically render a drop shadow behind whatever you draw next — a rectangle, a path, text, or an image — by setting four shadow properties on the context before the drawing call. The shadow is computed from the shape's alpha channel, so it follows the exact silhouette of what you draw, not just its bounding box.

The Four Shadow Properties

shadowColor sets the shadow's color (any CSS color, including semi-transparent rgba() values). shadowBlur sets how many pixels the shadow is blurred by — 0 gives a crisp hard-edged silhouette, larger numbers give a soft, spread-out glow. shadowOffsetX and shadowOffsetY shift the shadow horizontally and vertically in pixels relative to the shape, letting you control the apparent direction of the light source.

Example 1: A Basic Drop Shadow

<!DOCTYPE html>
<html>
<body>

<canvas id="shadowCanvas" width="280" height="180" style="border:1px solid #ccc;"></canvas>

<script>
const canvas = document.getElementById("shadowCanvas");
const ctx = canvas.getContext("2d");

ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 8;
ctx.shadowOffsetY = 8;

ctx.fillStyle = "#e76f51";
ctx.fillRect(60, 40, 180, 100);
</script>

</body>
</html>

Shadow properties stay active for every subsequent drawing operation until you change or reset them. That means if you draw several shapes in a row, they'll all get the same shadow — which is convenient for consistent styling, but easy to forget when you only want one shape to have a shadow.

  • shadowColor accepts any CSS color; using an rgba() with reduced alpha produces a more realistic, softer-looking shadow than a solid black.
  • shadowBlur of 0 (the default) disables blurring entirely, producing a sharp silhouette offset by shadowOffsetX/Y.
  • Positive shadowOffsetX moves the shadow right, negative moves it left; positive shadowOffsetY moves it down, negative moves it up.
  • Shadows apply to fillRect, strokeRect, fill(), stroke(), fillText(), strokeText(), and drawImage() alike.
  • Reset shadowColor to "transparent" (or shadowBlur/offsets back to 0) before drawing shapes that shouldn't have a shadow, to avoid it leaking onto later drawings.

Example 2: Glowing Text with a Colored Shadow

<!DOCTYPE html>
<html>
<body>

<canvas id="glowTextCanvas" width="320" height="120" style="border:1px solid #ccc;"></canvas>

<script>
const ctx2 = document.getElementById("glowTextCanvas").getContext("2d");
ctx2.fillStyle = "#0b0c10";
ctx2.fillRect(0, 0, 320, 120);

ctx2.shadowColor = "#66fcf1";
ctx2.shadowBlur = 20;
ctx2.shadowOffsetX = 0;
ctx2.shadowOffsetY = 0;

ctx2.font = "bold 40px Arial";
ctx2.fillStyle = "#c5c6c7";
ctx2.fillText("NEON", 40, 70);
</script>

</body>
</html>
Note: Setting shadowOffsetX and shadowOffsetY both to 0 while keeping a nonzero shadowBlur centers the blur directly behind the shape, producing a glow effect rather than a directional drop shadow.

Example 3: Resetting Shadows Between Shapes

<!DOCTYPE html>
<html>
<body>

<canvas id="cardsCanvas" width="310" height="200" style="border:1px solid #ccc;"></canvas>

<script>
const ctx3 = document.getElementById("cardsCanvas").getContext("2d");

// Card with a shadow
ctx3.shadowColor = "rgba(0, 0, 0, 0.4)";
ctx3.shadowBlur = 10;
ctx3.shadowOffsetX = 5;
ctx3.shadowOffsetY = 5;
ctx3.fillStyle = "#ffffff";
ctx3.fillRect(20, 20, 120, 160);

// Reset shadow before drawing the next shape
ctx3.shadowColor = "transparent";
ctx3.shadowBlur = 0;
ctx3.shadowOffsetX = 0;
ctx3.shadowOffsetY = 0;

ctx3.fillStyle = "#457b9d";
ctx3.fillRect(160, 20, 120, 160);
</script>

</body>
</html>
Note: Large shadowBlur values on many shapes can be noticeably slow to render, especially inside animation loops, because the browser recalculates the blur every frame. For performance-critical animations, consider pre-rendering the shadow once onto an offscreen canvas and reusing it as an image.
PropertyPurpose
shadowColorSets the shadow's color, including semi-transparent rgba() values
shadowBlurControls the blur radius in pixels; 0 is a sharp edge, higher values are softer
shadowOffsetXShifts the shadow horizontally, in pixels, relative to the shape
shadowOffsetYShifts the shadow vertically, in pixels, relative to the shape

Exercise: Canvas Shadows

What must be set for a shadow to actually become visible, even with shadowBlur set?