# Scanned and untagged PDFs that screen readers can't read

Source: https://easeweb.dev/learn/accessible-pdfs
Topics: Page structure > Downloadable PDFs and documents are accessible (WCAG 1.1.1, 1.3.1, 1.3.2)
The fix: Either publish the menu as an HTML page and link to that, keeping a PDF only as a print version that says the same, or replace the file with a tagged PDF exported from its source document with tags turned on, then checked. A scan with no source file has to be retyped, or run through OCR and tagged and checked by hand: OCR alone is not a fix.
Test with: screen reader
References: https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html https://www.w3.org/WAI/WCAG22/Understanding/meaningful-sequence.html https://www.w3.org/WAI/WCAG22/Understanding/conformance#conforming-alternate-version https://www.w3.org/WAI/WCAG22/Techniques/pdf/PDF7 https://www.w3.org/WAI/WCAG22/Techniques/pdf/PDF9 https://www.w3.org/WAI/WCAG22/Techniques/pdf/PDF21 https://www.w3.org/WAI/WCAG22/Techniques/pdf/PDF3 https://www.w3.org/WAI/WCAG22/Techniques/pdf/PDF1 https://www.gov.uk/guidance/publishing-accessible-documents https://support.microsoft.com/en-us/office/create-accessible-pdfs-064625e0-56ea-4e16-ad71-3aa33bb4b7ed https://pac.pdf-accessibility.org/en

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A neighbourhood café, Corner Kitchen, links its lunch menu from every page: "Lunch menu (PDF)". On screen the PDF looks like the card on the tables: the title, then two columns, soups and salads on the left and mains on the right, each dish with its price. The café made it in one of two ways, and each fails differently.

In the first, someone scanned the printed card on the office copier and uploaded the scan. Exporting from a design tool can give the same file: Canva's Flatten PDF option, often ticked so the print shop gets exactly what was designed, turns the words into an image too. A blind visitor follows the link, the PDF opens, and the screen reader says the file name and then nothing at all: the page is one picture, and there are no words in it. Selecting a line selects nothing, and searching for "soup" finds nothing. Zooming in shows a blurred photo of paper.

In the second, the menu was exported from a design app with its tags turned off. The words are real text, so the screen reader reads them, but as one run, in the order the file draws them: "Lunch menu. Soups and salads Mains. Tomato soup 6.50 Mushroom risotto 12.00. Green salad 7.00 Grilled chicken 13.50." The lines go straight across both columns, so each soup is followed by a main course, and nothing says the title and the two section names are headings. Pressing H to jump to the next heading finds none.

## Why it fails

A PDF the site links to is part of the site's content, and WCAG applies to it as it does to the page; the W3C keeps a set of PDF techniques for exactly that. The two forms fail different criteria:

- The scan is non-text content with no text alternative, which fails 1.1.1. Every word of the menu exists only as pixels, and an untagged PDF has no Figure tag on which alternative text could even be set.
- The untagged export fails 1.3.1 and 1.3.2. In a PDF, headings, lists and tables, and the order to read them in, are carried by tags, as HTML elements carry them in a page. With no tags, the title's size and the section names' weight are presentation only, and the reading order is whatever order the file happens to draw its text in. Here that runs across the columns, which changes the meaning: a price ends up next to the wrong dish.

A PDF that fails can still be part of a conforming site, if a conforming alternate version sits beside it: a page with the same content, kept as current, that people can reach from where they find the PDF. That is the first fix below.

## Who is affected

Menus, price lists, size guides, terms and brochures are often published only as PDFs, so a visitor who can't read the file has no other way to get what is in it, short of asking the café to read it out.

## What automation and AI miss

Page checkers such as axe test the page's own HTML. The PDF is a separate file they never open, so a site whose every document is a scan can pass them with no errors; all they see is a link, and the link is fine. This audit opens the PDFs a page links to, the first five on each page and each one once per run, and reads their bytes. A PDF with no font, no tags and no alternative text, only pictures, is reported: the code alone proves there is nothing in it to read. Every other linked document goes to a person as a lead, because whether it works depends on what is in it. An untagged PDF with text may lose a little structure or a lot. A tagged one may have its tags in the wrong order, a heading tagged as a paragraph, or a table tagged as loose text. Word and Excel files aren't opened at all.

Two shortcuts look like fixes and aren't. Running OCR on a scan ("make searchable") adds a hidden text layer, which gets past the "has text" test, but it adds no tags, and it misreads: "6.50" can come out as "650" and a column break as nothing. Some PDF viewers now run OCR on a scan for screen reader users themselves, with the same limits, and only in those viewers. Asking an AI tool or Acrobat's automatic tagging to "make the PDF accessible" usually sets a title and language and guesses the tags from the layout, and on a two-column page the guess often keeps the order straight across.

## Before: a scanned menu

```html
<a href="/files/lunch-menu.pdf">Lunch menu (PDF)</a>
```

```pdf
% lunch-menu.pdf: the catalog has no StructTreeRoot and no MarkInfo
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
% Page 1 draws one picture, the scan, across the whole page, and nothing else
q 595 0 0 842 0 0 cm /Im0 Do Q
```

The page's only content is the image `Im0`, drawn at the size of the page. The file uses no font, so there are no words in it to read, select, search or enlarge, and with no tag tree there is nowhere to put alternative text.

## Before: a menu exported without tags

```html
<a href="/files/lunch-menu.pdf">Lunch menu (PDF)</a>
```

```pdf
% lunch-menu.pdf, exported with tags turned off: no StructTreeRoot, no MarkInfo
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
% The text is drawn line by line, straight across both columns
BT /F2 24 Tf 72 760 Td (Lunch menu) Tj ET
BT /F1 13 Tf 72 720 Td (Soups and salads) Tj 240 0 Td (Mains) Tj ET
BT /F1 11 Tf 72 700 Td (Tomato soup 6.50) Tj 240 0 Td (Mushroom risotto 12.00) Tj ET
BT /F1 11 Tf 72 684 Td (Green salad 7.00) Tj 240 0 Td (Grilled chicken 13.50) Tj ET
BT /F1 11 Tf 72 668 Td (Lentil salad 7.50) Tj 240 0 Td (Bean chilli 11.00) Tj ET
```

The words are text in fonts, so they can be read, but nothing says what they are. The title is only larger (`24 Tf`), the section names only in a heavier font, and the order is the drawing order, which takes one line from each column in turn.

## After: the menu as a web page

```html
<a href="/lunch-menu">Lunch menu</a>

<!-- /lunch-menu -->
<h1>Lunch menu</h1>
<div class="menu">
  <section>
    <h2>Soups and salads</h2>
    <ul>
      <li>Tomato soup, 6.50</li>
      <li>Green salad, 7.00</li>
      <li>Lentil salad, 7.50</li>
    </ul>
  </section>
  <section>
    <h2>Mains</h2>
    <ul>
      <li>Mushroom risotto, 12.00</li>
      <li>Grilled chicken, 13.50</li>
      <li>Bean chilli, 11.00</li>
    </ul>
  </section>
</div>
<p><a href="/files/lunch-menu.pdf">Print version (PDF, 1 page)</a></p>
```

```css
/* Two columns where there is room, one on a phone; either way the order is the HTML's */
@media (min-width: 40rem) {
  .menu {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
  }
}
```

The menu is now text in the page, so a screen reader reads every dish, announces the title and both section names as headings, and reads each section as a list of three, one column after the other, because that is the order of the HTML. It also reflows on a phone, grows with the reader's text size, and can be searched and translated. The site links to the page, not the file.

The print version is optional. If you keep it, link it only from this page, make sure it says exactly what the page says, and replace it whenever the menu changes: the page counts as the PDF's conforming alternate version only while the two match. A print stylesheet on the page itself (`@media print`) can do the same job with nothing to keep in step.

## After: a tagged PDF exported from the source

```html
<a href="/files/lunch-menu.pdf">Lunch menu (PDF, 1 page)</a>
```

```pdf
% lunch-menu.pdf, exported from the source document with tags turned on
1 0 obj << /Type /Catalog /Pages 2 0 R /StructTreeRoot 6 0 R
  /MarkInfo << /Marked true >> /Lang (en)
  /ViewerPreferences << /DisplayDocTitle true >> >> endobj
% Each run of text is marked with its tag
/H1 << /MCID 0 >> BDC BT /F2 24 Tf 72 760 Td (Lunch menu) Tj ET EMC
/H2 << /MCID 1 >> BDC BT /F1 13 Tf 72 720 Td (Soups and salads) Tj ET EMC
/LBody << /MCID 2 >> BDC BT /F1 11 Tf 72 700 Td (Tomato soup 6.50) Tj ET EMC
…
% The tag tree reads one column, then the other:
% Document > H1, H2, L (3 × LI > LBody), H2, L (3 × LI > LBody)
```

Nobody writes this by hand: the authoring app writes it when the source document uses its own styles and tags are turned on. In Word, use the Heading styles for the title and section names and the list buttons for the dishes, give any picture alt text, then export with File > Save As > PDF > Options > "Document structure tags for accessibility". LibreOffice's PDF export has a "Universal Accessibility (PDF/UA)" option, and InDesign's has "Create Tagged PDF", with the reading order set in the Articles panel. Then open the file in a PDF checker such as PAC, fix what it reports in the source and export again, and listen to it with a screen reader.

A scan has no source to export. Retype it in the authoring app, or, in Acrobat Pro, run OCR, correct every word it is unsure of, add tags, and fix the reading order with the Reading Order tool, checking every word against the card.

## Which option to use

Both pass 1.1.1, 1.3.1 and 1.3.2. The page is usually the better home for something people read on screen and that changes often, such as a menu, a price list or opening hours: it costs one page in the site's own templates, needs no PDF tools, works the same in every browser and on every phone, and has no tags to check after each edit. The tagged PDF is the one to keep when the file itself is the point: an invoice, a signed agreement, terms someone saves, or a brochure designed for print. It costs an export with tags on and a check after every change, and a scan costs a retype or a careful repair. Many sites do both: a page for the content, and a tagged PDF as its print version.

## Implementation decisions

While the PDF is open in a checker, set what it needs to work as a document of its own. Each comes from the same export or from Acrobat's document properties:

- A title. Set the document title (File > Properties) and turn on "show document title" (DisplayDocTitle), so the window and the screen reader announce "Lunch menu", not "lunch-menu.pdf".
- A language. Set the document language, so a screen reader reads the words in the right voice. A passage in another language needs its own.
- Decoration as artifacts. Borders, background textures and page numbers are marked as artifacts, so they aren't read between the dishes.
- Prices that line up. When dishes and prices sit in two aligned columns of their own, tag them as a table with header cells, or keep each price in the same text run as its dish, as here.

Say on the link what it opens. A link named "Lunch menu (PDF, 1 page)" tells people a file is coming, which matters on a phone, and a link to a page needs no label at all.

Treat the PDFs a site already has as a list to work through. Start with the ones people need to buy or book (menus, price lists, size guides, terms), retire the ones nobody needs, and turn each remaining one into a page or a tagged PDF when it is next updated.

Interactive forms in PDFs, such as an order form with fields to fill in, raise more than this guide covers: every field needs a name, and the order of the fields needs checking. Build them as HTML forms where you can.

## Verify the fix

1. Open the menu, the page or the PDF, and select a sentence, then search for a word with Find. Both work, and the selection is the words shown.
2. Read it with a screen reader from the top. Every word is read, each section in full before the next, with each price straight after its dish.
3. Press H and L (in NVDA or JAWS) to jump between headings and lists. Each heading is found, at the level it looks, and each group of dishes is a list with the number of items shown.
4. Check the code. For the page, the headings and lists are in the HTML. For a PDF, PAC or Acrobat Pro's accessibility check finds a tag tree with no untagged content, a title and a language, and the tags match what each part is.
5. Where the page links a print version, open both and confirm the print version says exactly what the page says, with the same dishes and prices.

Record the OS, browser, PDF viewer and assistive-technology versions, the build, the date, and the actual result of each step. Repeat whenever the document is replaced, re-exported or edited.

## Limits

This is a starting pattern, not a guarantee for every document. The PDF code is cut down to the lines that matter: object numbers, fonts and coordinates are placeholders, and `…` stands for the rest of the page's tagged lines. Screen readers and PDF viewers handle untagged files differently, some guessing an order or running their own OCR, so test in the viewers your visitors use, not only one. This guide covers whether a document's words exist as text and its structure and order are tagged. It doesn't cover PDF forms, the contrast or text size inside a document, or Word and Excel files, which need their own app's checker. Test the complete journey with your target assistive technology.

---

Get this guide in your coding agent: MCP https://easeweb.dev/mcp (setup at https://easeweb.dev/services/developers)
