The HTML charset attribute
The HTML charset attribute on <meta> declares the page's character encoding. Its only valid value is utf-8. Put <meta charset="utf-8"> within the first 1024 bytes of the document, ideally as the first element in <head>.
Overview
The charset attribute declares which character encoding a page's bytes use. On <meta> it acts as the document's character encoding declaration, and the HTML Standard allows exactly one value, a case-insensitive match for utf-8, so UTF-8 works too.
Placement matters as much as the value. The whole element must sit within the first 1024 bytes of the file, a document may contain only one such declaration, and it cannot be combined with <meta http-equiv="content-type">, the alternative form of the same declaration.
The browser checks several sources. The main ones, in order, are a byte order mark at the start of the file, a charset in the HTTP Content-Type header, and a meta tag found by pre-scanning the first bytes. If none of those exist, the browser guesses, and the fallback the HTML Standard suggests for many locales is windows-1252.
A wrong guess garbles text. The UTF-8 bytes for é read as windows-1252 come out as é, which is why the standard requires a declaration even on a page that is pure ASCII today, since form input and script-built URLs still need a known encoding.
Syntax
<head>
<meta charset="utf-8">
<title>Page title</title>
</head>
Values
| Value |
|---|
The string utf-8, matched case-insensitively. It is the only conforming value. |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Café menu</title>
</head>
<body>
<p>Café, crème brûlée, 20 °C</p>
<p id="out"></p>
<script>
const bytes = new TextEncoder().encode('Café, crème brûlée, 20 °C');
const wrong = new TextDecoder('windows-1252').decode(bytes);
document.getElementById('out').textContent = 'Same bytes read as windows-1252: ' + wrong;
</script>
</body>
</html>
Best practices
- Make
<meta charset="utf-8">the first child of <head>, before the <title>, so it lands well inside the first 1024 bytes. - Save your files as UTF-8 in your editor. The declaration only describes the bytes, it does not convert them.
- Send
Content-Type: text/html; charset=utf-8from the server as well, because the HTTP header takes priority over the meta tag. - Drop
charsetfrom <script> and <link> tags. The HTML Standard lists it as obsolete on both, notes that scripts must already be UTF-8, and says to use an HTTPContent-Typeheader on a linked resource instead. - Leave the declaration out of srcdoc documents, which the HTML Standard says must not have one because their text is already decoded.