Skip to content

HTML entity, Unicode and CSS codes for accented letters

Named entities, decimal and hex references, CSS and JavaScript escapes and URL encoding for accented letters, plus when to skip entities and just use UTF-8.

Updated · 6 min read

Every accented letter can be written several ways in web code: as itself, as a named HTML entity, as a numeric reference in decimal or hex, as a CSS escape, and as a string escape in your programming language. All of them produce the same character. Every value below was recomputed from the code point rather than copied from another list.

What each form looks like

Take é, code point U+00E9:

FormValue
The characteré
HTML namedé
HTML decimalé
HTML hexé
CSS\E9
JavaScript, Java, C#, Python\u00E9
JavaScript ES6, PHP, Rust, Swift\u{E9}
URL%C3%A9

Acute and grave

CharEntityDecimalHexCSSJS
áááá\E1\u00E1
éééé\E9\u00E9
íííí\ED\u00ED
óóóó\F3\u00F3
úúúú\FA\u00FA
ýýýý\FD\u00FD
àààà\E0\u00E0
èèèè\E8\u00E8
òòòò\F2\u00F2
ùùùù\F9\u00F9

Circumflex and tilde

CharEntityDecimalHexCSSJS
ââââ\E2\u00E2
êêêê\EA\u00EA
îîîî\EE\u00EE
ôôôô\F4\u00F4
ûûûû\FB\u00FB
ãããã\E3\u00E3
ññññ\F1\u00F1
õõõõ\F5\u00F5

Diaeresis and umlaut

CharEntityDecimalHexCSSJS
ääää\E4\u00E4
ëëëë\EB\u00EB
ïïïï\EF\u00EF
öööö\F6\u00F6
üüüü\FC\u00FC
ÿÿÿÿ\FF\u00FF

The letters with their own shapes

CharEntityDecimalHexCSSJS
åååå\E5\u00E5
ææææ\E6\u00E6
çççç\E7\u00E7
øøøø\F8\u00F8
ßßßß\DF\u00DF
ðððð\F0\u00F0
þþþþ\FE\u00FE
œœœœ\153\u0153
šššš\161\u0161
łłłł\142\u0142

Note the last three rows. œ, š and ł sit in Latin Extended-A. Their names are in the HTML specification, but older parsers never knew them, so numeric references are safer outside Latin-1.

Capitals

CharEntityDecimalHex
ÁÁÁÁ
ÉÉÉÉ
ÍÍÍÍ
ÓÓÓÓ
ÚÚÚÚ
ÑÑÑÑ
ÜÜÜÜ
ÇÇÇÇ
ØØØØ
ÅÅÅÅ

The pattern holds across Latin-1: capitalise the entity name, and the decimal is 32 lower than the lowercase one.

What has no named entity at all

All 64 characters from U+00C0 to U+00FF have a named entity, and all 64 also work without the closing semicolon for historical reasons. Latin Extended-A mostly has names too, though eight letters do not: Ĕ, ĕ, ģ, Ĭ, ĭ, Ŏ, ŏ and the long s ſ.

Beyond that, nothing. There is no named entity for:

  • Romanian ș and ț, or their capitals
  • Vietnamese horn letters ơ and ư, and every tone letter from U+1EA0 to U+1EF9
  • Capital sharp s ẞ (U+1E9E)

For those, use a numeric reference such as ș, or write the character directly in a UTF-8 file.

Entities or plain UTF-8?

Plain UTF-8, nearly always. Write résumé in your markup and let the encoding carry it. Entities cost bytes and hurt readability.

The one thing you must get right is the declaration. Put the charset meta tag first in the head, before anything else:

<head>
  <meta charset="utf-8">
  <title>Café</title>
</head>

Also make sure the server sends Content-Type: text/html; charset=utf-8, that your database and connection are UTF-8, and that your editor saves as UTF-8 without a byte order mark. Almost every case of é appearing where é should be comes from one of those three, not from a missing entity.

Entities still earn their place in generated markup and email templates, where you cannot control the encoding. And you always need &amp;, &lt; and &gt; regardless.

CSS escapes

CSS escapes take one to six hexadecimal digits after a backslash:

.price::after { content: "\20AC"; }   /* € */
.note::before { content: "\E9"; }     /* é */

The catch is termination. A single space after the escape is swallowed by it, so a real space must be doubled, or pad the escape to six digits:

content: "\0000E9 caf";   /* padded, no ambiguity */

In JavaScript, use CSS.escape() rather than hand rolling this.

URLs

Percent encoding works on UTF-8 bytes, so accented letters take two bytes each:

CharURL formCharURL form
é%C3%A9ñ%C3%B1
ü%C3%BCç%C3%A7
ß%C3%9Fø%C3%B8
à%C3%A0ô%C3%B4
ł%C5%82ș%C8%99

Single byte forms like %E9 are a Latin-1 legacy and are not interoperable. Use encodeURIComponent() rather than building these by hand.

Normalisation, the bug you cannot see

Unicode allows é to be one code point (U+00E9) or two (e plus the combining acute U+0301). They look identical and compare as unequal.

Normalise before you compare, store or index:

const a = "café";    // é as one code point
const b = "café";   // e plus a combining acute

a === b;                                    // false
a.length === b.length;                      // false: 4 and 5
a.normalize("NFC") === b.normalize("NFC");  // true

Serve and store NFC, because that is what the web expects and what most keyboards produce. If you need to strip marks for a search index, decompose first and remove the combining marks, then handle the letters that have no combining form at all: ł, ø, đ, æ, œ, ß, þ and ð will survive decomposition untouched and need an explicit map. That is exactly what Remove accents from text implements, and Add accents to text reverses.

For the character level background see What is a diacritic? Accent marks explained and Common accent mistakes and the confusable characters, and for typing rather than encoding see How to type accents on Windows (Alt codes and layouts), How to type accents on a Mac (Option key and press-and-hold) and Alt codes for accented letters: the complete verified list. Language specific letter sets are at Romanian and Vietnamese, and every character has its own reference page from Accent Letter.

FAQ

Do I still need HTML entities for accented letters?

Usually not. If your page is served as UTF-8 and declares it with a meta charset tag, you can write é directly in the markup. Entities remain useful in generated markup, email templates and anywhere the encoding is uncertain.

Which accented letters have named HTML entities?

All 64 characters in the Latin-1 Supplement range have one, such as eacute and ntilde. Most Latin Extended-A letters have HTML5 names too, but Romanian comma letters, Vietnamese tone letters and capital sharp s have none.

What is the CSS escape for é?

Backslash E9. CSS escapes take one to six hexadecimal digits, and a single space after the escape is consumed as a terminator, so a real space has to be doubled.

Why does my search for résumé not find the word?

Probably normalisation. The accented letter can be stored as one code point or as a base letter plus a combining mark. Normalise both the query and the index to NFC before comparing.

How do I put an accented letter in a URL?

Percent encode the UTF-8 bytes. é becomes %C3%A9 and ñ becomes %C3%B1. The old Latin-1 style single byte form such as %E9 is not interoperable.

By language: Spanish, French, German, Portuguese, Romanian, Vietnamese