HTML5 Features

Canvas, video and audio, data-* attributes, the template element, and semantic input types like tel and url.

<video> and <audio>

HTML5 added native media playback — no Flash plugin, no third-party player required:

HTML
<video controls width="640" poster="preview.jpg">
    <source src="lesson.mp4" type="video/mp4">
    <source src="lesson.webm" type="video/webm">
    Your browser doesn't support HTML5 video.
</video>

<audio controls>
    <source src="podcast.mp3" type="audio/mpeg">
    Your browser doesn't support HTML5 audio.
</audio>
  • controls — shows the browser's built-in play/pause/volume/seek UI.
  • Multiple <source> elements let the browser pick the first format it supports (useful since not every browser supports every video codec).
  • The text between the tags is a fallback shown only in browsers old enough not to support the element at all.
  • Useful boolean attributes: autoplay (generally blocked by browsers unless also muted), loop, muted, preload.
HTML
<video autoplay muted loop>
    <source src="background.mp4" type="video/mp4">
</video>

<canvas>

<canvas> is a blank, scriptable drawing surface — HTML provides the element, but all the actual drawing happens through JavaScript (the Canvas 2D API, or WebGL for 3D):

HTML
<canvas id="chart" width="400" height="200"></canvas>
Javascript
const canvas = document.getElementById('chart');
const ctx = canvas.getContext('2d');

ctx.fillStyle = '#3b82f6';
ctx.fillRect(20, 20, 150, 80); // x, y, width, height

<canvas> is used for things markup and CSS can't express well: charts, image editors, games, generative graphics. It's a big topic on its own — the key thing to know here is that the element itself is just a pixel surface with no built-in shapes or scene graph; everything is imperative drawing calls.

data-* attributes

Custom data attributes let you attach arbitrary data to an element without inventing a non-standard attribute or abusing class:

HTML
<button data-user-id="482" data-role="admin">Delete user</button>
Javascript
const button = document.querySelector('button');
console.log(button.dataset.userId); // "482" — camelCase in JS, kebab-case in HTML
console.log(button.dataset.role);   // "admin"

Any attribute prefixed with data- is guaranteed by the spec to never collide with a future standard HTML attribute, and is automatically exposed through JavaScript's element.dataset object (with data-user-id becoming dataset.userId). This is the standard way to embed small pieces of state directly in markup for JavaScript (or CSS attribute selectors) to read later.

<template>

<template> holds markup that is parsed by the browser but not rendered and not executed until JavaScript explicitly clones it into the document. It's the standard way to define a reusable chunk of HTML for repeated UI (list items, cards) without writing string concatenation in JavaScript:

HTML
<template id="card-template">
    <li class="card">
        <h3 class="card-title"></h3>
        <p class="card-body"></p>
    </li>
</template>

<ul id="card-list"></ul>
Javascript
const template = document.getElementById('card-template');
const list = document.getElementById('card-list');

function addCard(title, body) {
    const clone = template.content.cloneNode(true);
    clone.querySelector('.card-title').textContent = title;
    clone.querySelector('.card-body').textContent = body;
    list.appendChild(clone);
}

addCard('Flexbox', 'A one-dimensional layout model.');

Any <img>, <script>, or <video> inside a <template> doesn't load or run until the content is cloned out — the browser treats everything inside as inert until that point.

Semantic input types: tel and url

These were mentioned briefly under forms, but they're worth calling out as part of HTML5's broader theme: letting the browser understand what kind of data an input expects, rather than treating every field as a generic text box.

HTML
<input type="tel" name="phone" placeholder="+1 555 123 4567">
<input type="url" name="website" placeholder="https://example.com">

On mobile, type="tel" brings up a numeric phone keypad, and type="url" brings up a keyboard with . and / easily accessible — small details, but they meaningfully improve the experience of filling out a form on a phone, and they cost nothing beyond picking the right attribute value.

Common mistakes

  • Using <canvas> for content that's actually static and better expressed in HTML/CSS (a card layout, an icon) — canvas content isn't selectable text, isn't accessible to screen readers by default, and isn't indexed by search engines.
  • Forgetting a fallback message inside <video>/<audio> for the rare case a browser doesn't support the element at all.
  • Reading data-* attributes with getAttribute('data-user-id') when element.dataset.userId is simpler and handles the kebab-case-to-camelCase conversion automatically.
  • Putting live, already-running content inside <template> and expecting it to behave normally — scripts and media inside a template don't execute until the content is cloned into the actual document.