The HTML abbr tag: mark abbreviations people can understand

Wrap a short form in an abbr element and put the full words in its title. The tooltip only helps mouse users, so spell the term out the first time it appears.

The <abbr> element marks an abbreviation or acronym. Put the full form in its title attribute: <abbr title="Statement of Work">SOW</abbr>. With a mouse, resting on the word shows the title as a tooltip.

That tooltip is usually not available to touch and keyboard users, so the reliable pattern is to spell the term out in the text the first time.

Compare the two versions below. Hover the first "SOW" with a mouse, then try the same on a phone.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>abbr with title vs expanded text</title>
<style>
  body { margin: 0; padding: 16px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  .box { background: #fff; border-radius: 10px; padding: 12px 14px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, .08); }
  h3 { margin: 0 0 6px; font-size: 13px; color: #5b6270; }
  p { margin: 0; font-size: 16px; line-height: 1.5; }
  .note { font-size: 13px; color: #5b6270; background: #fff7e6; border-radius: 8px; padding: 10px 12px; line-height: 1.45; }
</style>
</head>
<body>
<div class="box">
  <h3>1. title only</h3>
  <!-- the expansion lives only in the title tooltip -->
  <p>Send the <abbr title="Statement of Work">SOW</abbr> before Friday.</p>
</div>

<div class="box">
  <h3>2. Expanded on first use</h3>
  <!-- the words are in the text, so everyone reads them -->
  <p>Send the Statement of Work (<abbr>SOW</abbr>) before Friday. The <abbr>SOW</abbr> needs a signature.</p>
</div>

<p class="note"><b>With a mouse:</b> rest the pointer on "SOW" in box 1 and a tooltip appears.<br>
<b>On a phone or with the keyboard:</b> box 1 usually shows no expansion at all. Box 2 reads the same for everyone.</p>
</body>
</html>
Box 1 keeps the meaning in a tooltip. Box 2 puts it in the sentence.

The markup is the same element in both boxes. The difference is where the full words live: in an attribute only some readers can reach, or in the text everyone reads.

What abbr does and does not do

<abbr> is an inline element with no behaviour of its own. It says "this word is a short form". The only visible effects come from the browser's default style and from the title attribute.

<p>Send the <abbr title="Statement of Work">SOW</abbr> by Friday.</p>
  • Semantics: tools and scripts can find every abbreviation on the page with querySelectorAll('abbr').
  • Tooltip: only when title is present, and only on mouse hover.
  • Style: a dotted underline in many browsers, but not the same everywhere.

title is optional. An <abbr> without it is still valid and still marks the word as a short form.

Who sees the title tooltip

The tooltip is drawn by the browser, not by the page. It appears after the pointer rests on the word for a moment. You cannot style it or change its delay.

A mouse gets the tooltip. A tap and the Tab key usually get nothing.
A mouse gets the tooltip. A tap and the Tab key usually get nothing.
  • Touch screens: there is no hover, so tapping the word usually shows nothing.
  • Keyboard: <abbr> is not focusable, so Tab skips it and nothing opens.
  • Screen readers: whether the title is read out depends on the reader and its settings. Do not count on it.

The title attribute tooltip guide covers these limits for title on any element. For <abbr>, the fix is mostly about writing, not code.

Expand the term the first time

Write the full words once, with the short form in brackets. After that, the short form alone is fine, because the reader has already seen it spelled out.

The meaning sits in the text, so it reaches every reader.
The meaning sits in the text, so it reaches every reader.
<p>Send the Statement of Work (<abbr>SOW</abbr>) by Friday.</p>
<p>The <abbr title="Statement of Work">SOW</abbr> needs a signature.</p>

A title on the later uses is a bonus for mouse users who jump into the middle of the page. It does not replace the first expansion.

For long documents with many terms, a glossary at the end helps too. The finished example builds one from the markup.

Styling the underline

The HTML spec suggests a dotted underline for abbr[title], and browsers do not all draw it the same way. A CSS reset can remove it. If the underline matters to your design, set it yourself.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Styling abbr</title>
<style>
  body { margin: 0; padding: 16px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  ul { list-style: none; margin: 0 0 14px; padding: 0; background: #fff; border-radius: 10px; box-shadow: 0 2px 8px rgba(0, 0, 0, .08); }
  li { padding: 10px 14px; font-size: 15px; border-bottom: 1px solid #eceef1; }
  li:last-child { border-bottom: 0; }
  code { font: 12px ui-monospace, Consolas, monospace; color: #5b6270; display: block; margin-top: 2px; }

  .reset  { text-decoration: none; }                    /* what many resets do */
  .dotted { text-decoration: underline dotted; text-underline-offset: 3px; }
  .border { text-decoration: none; border-bottom: 1px dashed #2563eb; }

  /* CSS-only tooltip: shows on hover and on keyboard focus */
  .tip { position: relative; text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
  .tip::after {
    content: attr(data-title);        /* read the text from the attribute */
    position: absolute; left: 0; top: calc(100% + 6px); z-index: 1;
    width: max-content; max-width: 220px; padding: 6px 9px; border-radius: 6px;
    background: #1d2330; color: #fff; font-size: 13px; line-height: 1.35;
    opacity: 0; pointer-events: none; transition: opacity .15s;
  }
  .tip:hover::after, .tip:focus::after { opacity: 1; }
  .tip:focus { outline: 2px solid #2563eb; outline-offset: 2px; border-radius: 2px; }
  .twice::after { content: attr(title); }   /* same tooltip, but reads title */

  h3 { margin: 0 0 6px; font-size: 13px; color: #5b6270; }
</style>
</head>
<body>
<h3>Underline styles</h3>
<ul>
  <li><abbr title="Application Programming Interface">API</abbr> browser default<code>no CSS</code></li>
  <li><abbr class="reset" title="Application Programming Interface">API</abbr> removed by a reset<code>text-decoration: none</code></li>
  <li><abbr class="dotted" title="Application Programming Interface">API</abbr> set on purpose<code>underline dotted; text-underline-offset: 3px</code></li>
  <li><abbr class="border" title="Application Programming Interface">API</abbr> dashed border<code>border-bottom: 1px dashed</code></li>
</ul>

<h3>CSS tooltips (hover, or Tab to focus)</h3>
<ul>
  <li><abbr class="tip twice" tabindex="0" title="Service Level Agreement">SLA</abbr> reads title: two tooltips on hover<code>content: attr(title)</code></li>
  <li><abbr class="tip" tabindex="0" data-title="Service Level Agreement">SLA</abbr> reads data-title: one tooltip<code>content: attr(data-title)</code></li>
</ul>
</body>
</html>
The default, a reset, two deliberate styles, and two CSS tooltips. Hover, or press Tab to reach the last two.
Goal CSS
Dotted underline everywhere text-decoration: underline dotted;
More space under the text text-underline-offset: 3px;
No underline text-decoration: none;
A line under the whole box border-bottom: 1px dashed;
A "help" pointer on hover cursor: help;

text-decoration is set on the <abbr> element itself. A rule on a parent paragraph does not remove it, so look for a reset that targets abbr or *.

A CSS-only tooltip that also opens on focus

A pseudo-element can show the full form in your own style. content: attr(...) copies an attribute's text into ::after. CSS ::before and ::after explains how pseudo-elements are placed.

abbr[data-title] { position: relative; }
abbr[data-title]::after {
  content: attr(data-title);
  position: absolute; left: 0; top: calc(100% + 6px);
  opacity: 0; pointer-events: none;
}
abbr[data-title]:hover::after,
abbr[data-title]:focus::after { opacity: 1; }

Add tabindex="0" to each <abbr> so the Tab key can reach it, and :focus shows the tooltip for keyboard users.

Notice the attribute. If the CSS reads title, the browser still shows its own tooltip on hover, and the reader sees two.

The second row of the demo reads data-title instead, so only your tooltip appears. The pure HTML tooltip guide covers CSS tooltips for any element.

abbr or dfn?

<dfn> marks the place where a term is defined. The sentence or paragraph around it is the definition. Browsers usually show it in italics.

abbr labels a short form. dfn marks where a term is explained.
abbr labels a short form. dfn marks where a term is explained.
<p>A <dfn id="sla"><abbr title="Service Level Agreement">SLA</abbr></dfn>
is the response time we promise each customer.</p>

Nesting them says both things: this is a short form, and this is where it is defined. Give the <dfn> an id and later mentions can link to it with href="#sla".

A finished example: popups and a glossary

This paragraph uses four abbreviations. A short script turns each <abbr title> into a term you can tap, click or Tab to, and lists every term in a glossary below.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Abbreviations with popups and a glossary</title>
<style>
  body { margin: 0; padding: 16px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  article { background: #fff; border-radius: 10px; padding: 14px 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, .08); }
  p { margin: 0 0 10px; font-size: 15px; line-height: 1.6; }
  abbr {
    text-decoration: underline dotted; text-underline-offset: 3px;
    cursor: help; border-radius: 3px;
  }
  abbr:focus { outline: 2px solid #2563eb; outline-offset: 1px; }
  abbr.open { background: #e8f0fe; }
  #pop {
    position: absolute; z-index: 10; max-width: 240px;
    padding: 7px 10px; border-radius: 7px;
    background: #1d2330; color: #fff; font-size: 13px; line-height: 1.4;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .2);
  }
  h2 { font-size: 14px; margin: 14px 0 6px; color: #5b6270; }
  dl { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; font-size: 14px; }
  dt { font-weight: 700; }
  dt abbr { text-decoration: none; cursor: auto; }
  dd { margin: 0; }
</style>
</head>
<body>
<article>
  <p>Our <abbr title="Customer Relationship Management">CRM</abbr> logs every call. When the
  <abbr title="Interactive Voice Response">IVR</abbr> hands a caller to an agent, the
  <abbr title="Average Handle Time">AHT</abbr> clock starts.</p>
  <p>We report <abbr title="Average Handle Time">AHT</abbr> weekly against the
  <abbr title="Service Level Agreement">SLA</abbr>, and flag any week where the
  <abbr title="Interactive Voice Response">IVR</abbr> drops more than usual.</p>
  <p style="font-size:13px;color:#5b6270">Tap, click or Tab to an underlined term. Esc closes.</p>

  <h2>Glossary</h2>
  <dl id="glossary"></dl>
</article>
<div id="pop" role="tooltip" hidden></div>

<script>
  const pop = document.getElementById('pop');
  const seen = new Map();  // short form -> expansion, for the glossary
  let current = null;

  document.querySelectorAll('abbr[title]').forEach((ab) => {
    const full = ab.title;
    ab.dataset.full = full;
    ab.removeAttribute('title');       // no second, native tooltip
    ab.tabIndex = 0;                   // reachable with Tab
    seen.set(ab.textContent.trim(), full);

    ab.addEventListener('focus', () => show(ab));
    ab.addEventListener('click', () => show(ab));
    ab.addEventListener('blur', hide);
  });

  function show(ab) {
    if (current && current !== ab) current.classList.remove('open');
    current = ab;
    pop.textContent = ab.dataset.full;
    pop.hidden = false;
    ab.classList.add('open');
    ab.setAttribute('aria-describedby', 'pop');  // screen readers can read it as a description
    // place under the term, but keep it inside the window
    const r = ab.getBoundingClientRect();
    const left = Math.min(r.left, innerWidth - pop.offsetWidth - 8);
    pop.style.left = Math.max(8, left) + scrollX + 'px';
    pop.style.top = r.bottom + 6 + scrollY + 'px';
  }

  function hide() {
    if (!current) return;
    current.classList.remove('open');
    current.removeAttribute('aria-describedby');
    current = null;
    pop.hidden = true;
  }

  document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hide(); });
  document.addEventListener('click', (e) => { if (!e.target.closest('abbr')) hide(); });

  // build the glossary from the same abbr elements, A to Z
  const dl = document.getElementById('glossary');
  [...seen].sort((a, b) => a[0].localeCompare(b[0])).forEach(([short, full]) => {
    dl.insertAdjacentHTML('beforeend', `<dt><abbr>${short}</abbr></dt><dd>${full}</dd>`);
  });
</script>
</body>
</html>
Each term opens a popup on tap, click or focus. The glossary is built from the same abbr elements.
  1. Move the title: the script copies title into data-full and removes title, so the native tooltip never doubles the popup.
  2. Make it focusable: tabIndex = 0 puts each term in the Tab order.
  3. One popup for all: a single positioned <div> is filled and moved under the active term, and kept inside the window.
  4. Close it: on blur, on Escape, and on a click outside a term.
  5. Build the glossary: a Map collects each short form once, sorted A to Z into a <dl>.

The glossary is plain text, so it reaches every reader no matter how they browse. Keep expanding terms on first use as well.

When it does not work

What you see Cause Fix
The tooltip never shows on a phone title needs hover, and touch has none Expand on first use, or add a tap popup
Tab never reaches the term <abbr> is not focusable Add tabindex="0"
No underline A reset sets text-decoration: none Set underline dotted on abbr yourself
The custom tooltip is cut off A parent has overflow: hidden or auto Move the popup outside the parent, as the glossary demo does
Two tooltips on hover CSS reads title, and the browser shows it too Read data-title, or remove title with a script
A validator flags <acronym> <acronym> is obsolete Replace it with <abbr>

A page full of abbreviations is often a spec, a report or a handbook. Sent as an .html file, it may open as plain code on a phone, and a screenshot cannot show a single popup.

To send the working version, paste the page into a NOS document and choose Create share link. HTML to link walks through it.

The page renders as written and its scripts run, so the people you send it to can tap each term themselves. If you add terms later, the same link shows the new version.

Questions people ask

What is the abbr tag in HTML?

It is an inline element that marks an abbreviation or acronym, such as <abbr title="Search Engine Optimization">SEO</abbr>. The optional title attribute holds the full form. Browsers show that title as a tooltip when a mouse rests on the word.

Why does the abbr tooltip not show on my phone?

The title tooltip appears on hover, and a touch screen has no hover. Tapping the word usually shows nothing. Write the full form in the text on first use, or add a popup that opens on tap, as in the finished example.

Is the acronym tag still valid?

No. <acronym> is obsolete in HTML. Browsers still display the text, but validators flag it. Use <abbr> for both abbreviations and acronyms.

How do I remove or change the dotted underline under abbr?

Set text-decoration on the element, for example abbr[title] { text-decoration: none; } to remove it, or text-decoration: underline dotted; text-underline-offset: 3px; to set it on purpose. If you remove it, give readers another hint that the word has an explanation.

What is the difference between abbr and dfn?

abbr says a word is a short form. dfn marks the place where a term is defined, and the sentence or paragraph around it is the definition. They can be nested: <dfn><abbr title="Service Level Agreement">SLA</abbr></dfn>.

Keep reading