Front-end education for the real world. Since 2018.





A guide to creating accessible PDFs using free tools

Steve Frenzel

Topic: A11y

Before we look at what free alternatives there are for creating and checking PDFs, you should ask yourself the following question: do I really need to create a PDF, or could I create a website or write an email instead?

If the answer to that is “no” or even “I don’t know”, I recommend reading Inaccessible PDFs? How to know when to use HTML webpages instead of PDFs by Whitney Lewis.

If the answer was “yes”, I’m going to show you how to do the following things using a practical example:

  • Creating an accessible PDF using LibreOffice
  • Doing a quick structure check with a text editor
  • Testing for PDF/UA and WCAG conformance on the axes4 website
  • Checking our documents with different screenreaders (JAWS, NVDA and VoiceOver)

Why I’m writing thispermalink

As I write this, I am in the application phase of finding a new role. Every now and then, I am offered the option to have form fields filled in automatically by uploading my resume.

I created my resume in Pages and selected the “On” option under “Advanced Options” and “Accessibility” when exporting. I did this in the hope that it would be accessible and machine-readable from a technical point of view.

After uploading the resume, my first name was always displayed as “Mastodon” and many fields were filled in incorrectly, or not at all. Since “Mastodon” is not my first name, I suspected that there was some kind of technical problem. So, for the nth time, I researched how to create and test accessible PDFs, and for the nth time, I was told that this was only possible with Adobe Acrobat Reader Pro. I didn’t feel like throwing my money at a big corporation, so I frantically continued searching for a way to make my wish come true.

I quickly found an answer after asking on Mastodon, thanks to Grant, who pointed me to the official accessibility documentation and Eric Eggert, who showed me how to test it for PDF/UA and WCAG conformance.

Using LibreOffice to create and export accessible PDFspermalink

Often ridiculed by me and rarely needed, I wanted to give LibreOffice a real chance this time, so I transferred my resume manually and first got an overview of what the problems actually are.

Requirements for accessible PDFs in LibreOffice

PDFs are subject to very similar accessibility requirements as websites. Let’s take a look at them (taken from the Universal Accessibility (PDF/UA) documentation):

  • The document title is set.

This is not the visible main heading, but the title of the document, think metadata.

  • The document language is set, or all styles in use have the language property set.

The language for the document is set automatically. However, if there are sections in other languages, these must be adjusted accordingly. Go to “Tools”, “Languages” and select the appropriate option.

  • All images, graphics, OLE objects have an alternate (alt) text or a title.

Graphics must either have a meaningful description or be marked as decorative. Got to “Format”, “Alt Text…” and either enter the text or tick the “Decorative” box. Check out What’s the alternative? How to write good alt text if you need help writing alternative text.

  • Tables do not contain split or merged cells.
  • Only integrated numbering is used, no manual numbering. For example, do not type “1.”, “2.”, “3.” at the beginning of paragraphs.

If numbers are generated, this should happen automatically and they should not be added manually. Example: Multiple lines of text are converted into a semantically correct element using “Ordered List” instead of adding the numbers yourself. Go to “Styles” and select “Numbering 123 List Style”.

  • Hyperlink texts without the underlying hyperlinks.

Texts marked as hyperlinks should contain the corresponding path. This warning appears when you create a hyperlink and then remove the path it contains using “Remove Hyperlink,” which you shouldn’t; just leave it be!

  • The contrast between text and the background meets the WCAG specification.

See Testing Color Contrast in Non-Web Documents and Images.

  • No blinking text.
  • No footnotes or endnotes.
  • Headings must increase sequentially with no skips, for example, you cannot have Heading 1, Heading 3, and no Heading 2.
  • Text does not convey additional meaning with (direct) formatting.

If the font or style for text is changed, this must not be applied to the text itself, but only to the semantic element itself representing this element. Example: All Heading 2 elements should be italic and in Comic Sans. Select the appropriate element either directly in the document or in the right-hand sidebar, go to “Styles” and select “Edit Style…” and change it accordingly.

Some of these points apply to our use case, as we will need headings, paragraphs, lists, hyperlinks, and a decorative image for the resume. If you work in web development and know a little about accessibility, these pain points should be very familiar to you.

Now that we know all the requirements, we can get started!

Displaying accessibility problems and warnings

On the right-hand side, you can click on “Accessibility Check” to display the corresponding warnings and notes. I have also selected “Entire page” under “Zoom” and “Formatting Marks” under “View.” This gives me an overview of the entire page and allows me to see where elements such as paragraphs, line breaks, or lists are located.

Screenshot of the LibreOffice user interface showing a document with text and an Accessibility Check panel on the right hand side. Inside the panel are one error and multiple warnings shown.

Not very pretty, but the good thing is that we only have one problem and a handful of warnings! The problem with the missing page title is quickly solved by clicking on the “Fix…” button and entering the title for the document, “Resume Steve Frenzel”:

Screenshot of the LibreOffice user interface highlighting a dialog for the document title. The input field contains the words “Resume Steve Frenzel”.

Creating a heading structure

Before we look at the warnings for links, I want to start by creating a hierarchy using headings. On the right-hand side, you can either select “Properties” or use the select element at the top left of the toolbar.

Screenshot of the LibreOffice user interface with two big arrows. One points to a select element in the toolbar on top, one points to the same element inside the panel on the right hand side. Both of them have the option “Default Paragraph Style” selected.

To do this, we highlight the relevant text and select, for example, “Heading 1,” “Heading 2,” and so on.

Screenshot of the LibreOffice user interface highlighting two warnings inside the Accessibility Check panel, “Avoid new empty lines between numbered paragraphs.”.

That looks much clearer already. However, there are now two warnings for “Avoid new empty lines between numbered paragraphs.”

Before we look at how to solve this, let’s add the lists.

Adding lists

Lists can be added either via “Format,” “Lists,” and “Unordered List,” or via the toolbar and the button element with the list icon:

Screenshot of the LibreOffice user interface highlighting the icon to create unordered lists with a big arrow. Below are multiple “Avoid new empty lines between numbered paragraphs.” Warnings highlighted.

Our structure is coming along nicely, but what’s that: more warnings?! Let’s see how we can get rid of those.

Avoiding empty lines between paragraphs

By removing the empty paragraphs between headings, lists, and so on, we can significantly tidy up the “Accessibility Check” section:

Screenshot of the LibreOffice user interface showing text with different kinds of headings, as well as unordered lists in-between. Inside the Accessibility check panel are multiple warnings for “Missing ‘name’ property of hyperlink.” and “Hyperlink text is the same as the link address”.

The warnings have disappeared, but now the spacing between the “Heading 3” elements is virtually non-existent. “Heading 1” and “Heading 2” are fine for me.

To create a better visual hierarchy, we can go to “Styles” and “Edit styles…” and adjust the spacing under “Spacing” in “Indents & Spacing.”

I chose a value of 0.20 and checked the box next to “Do not add space between paragraphs of the same style” so that these values are applied above and below the element.

Screenshot of the LibreOffice user interface with a “Paragraph Style” dialog open. Inside, the “Spacing” section is highlighted, containing two options: “Above paragraph” and “Below paragraph”. Both values are 0.2.

Now our document looks less squashed and we can take care of the warning about the links.

There are two warnings, namely “Missing ‘name’ property of hyperlink.” and “Hyperlink text is the same as the link address […]”. Here is our list of links:

What we need to do is give the link itself an accessible name and replace the URL with a different word. For example:

To do this, select the relevant word and open the context menu via “Insert” and “Hyperlink” in the toolbar (or CMD + K on macOS). For the email address, select “Mail” and enter the email address under “Recipient:”.

For hyperlinks, we select “Internet” and paste the URL under “Hyperlink settings” and “URL” (it is automatically pasted from the clipboard).

Screenshot of the LibreOffice user interface with two big arrows pointing to the accessibility warning “Hyperlink test is too short.”. It also highlights a “Hyperlink” dialog, where one can enter values for websites, emails and documents.

Although the warning about the hyperlink text has disappeared, two of the six links are now too short. It’s “only” a warning, but my goal is to have zero errors or warnings, so we’re going to fix that. “Email” becomes “Send email” and ‘Blog’ becomes “Read blog.”

Nice! All that’s missing now is the accessible name for the links. To do this, we click the corresponding “Fix…” button and enter the appropriate name:

Screenshot of the LibreOffice user interface highlighting a dialog titled “Enter a name of the hyperlink.”. It contains a text input with the value “Send email” in it.

Adding a different font

This resume looks very plain, doesn’t it? I’m not interested in winning a design award, but I would like to make it a little more appealing by using a different font. I’ve chosen “Graphik” for the headings and “Atkinson Hyperlegible Next” for the paragraphs.

Let’s start by applying the style to the main heading:

Screenshot of the LibreOffice user interface with a big arrow pointing to the accessibility warning “The text formatting conveys additional meaning.”

It looks better (in my opinion), but we got the warning “The text formatting conveys additional meaning.” This warning appears when we apply the new font directly to the text instead of using it globally for all main headings.

A better approach is to change the font under “Styles,” “Edit Style…,” “Font,” and “Family.” Alternatively, you can select the corresponding element, right-click, and access it in the context menu via ‘Paragraph’ and “Edit Style…”.

Adding a decorative image

Perfect, no more accessibility problems or warnings anymore! Now let’s add a visual accent to the document with a visual separator. The toolbar has a button called “Insert line” (visualized by a diagonal line), which we can use to add the decorative image:

Screenshot of the LibreOffice user interface with a big arrow pointing to a button inside the tool bar on top. The icon of the button shows a diagonal line.

Interestingly, we do not receive a warning in the “Accessibility Check” section that this image has no alternative text or that it has not been marked as decorative. However, as we are aware of this issue, we will fix it immediately.

By right-clicking on the image (or selecting “Format” and “Alt Text…”), we can check the “Decorative” box. Done!

Screenshot of the LibreOffice user interface showing a dialog called “Alt Text”. It contains input fields for “Text” and “Alt Text”, as well as a ticked checkbox labelled “Decorative”. A big arrow points to that checkbox.

Exporting it as accessible PDF

Before exporting, we check whether we have implemented our elements correctly. To do this, we open the side panel under “Tools” and “Navigator,” which shows us semantic elements in the document. Although no paragraphs are displayed, all headings, hyperlinks, and images are shown as expected. Nice, moving on!

Screenshot of the LibreOffice user interface showing eleven highlighted heading elements. The “Navigator” side panel visualises the hierarchy of these elements, as well as hyperlinks and images.

Go to “File”, “Export As” and “Export as PDF…” and tick the box labelled “Universal Accessibility (PDF/UA)” to make sure it’s meeting the technical requirements for an accessible PDF:

Screenshot of the LibreOffice user interface showing a dialog titled “PDF Options”. A big arrow is pointing to a ticked checkbox labelled “Universal Accessibility (PDF/UA)”.

Testing the PDFpermalink

Let’s start with a very simple test to make sure our document structure is correct. As I’m on MacOS, I’m using the native Preview and TextEdit apps here but you can choose whatever is available to you.

After opening the PDF with Preview, we select all the text via CMD + A and copy it using CMD + C.

Screenshot of the PDF opened in Preview on MacOS with all text highlighted in light blue.

Now, we’re going to paste it into an empty TextEdit document with CMD + V.

Screenshot of TextEdit on MacOS showing all text of the PDF, including custom fonts, font sizes, formatting, lists and links.

So, what are we looking for? We’re checking for:

  • A logical reading order without mixed up content
  • Random text or characters

As both are not the case, we can assume our document is fine. Let’s move on to check if it fulfils the PDF/UA and WCAG requirements on axes4.

Checking PDF/UA and WCAG requirements on axes4

Head over to the axes4 website and either drag and drop your document where it says “Drag and drop your PDF here” or upload it by selecting the “select file” button.

Screenshot of the axes4 website showing the drag and drop area for PDFs. A big arrow is pointing to the words “Drag and drop your PDF here”.

Great, our document meets all requirements! In the “Document” and “Test Report” sections, you will find detailed information about the document and which criteria were checked.

Screenshot of the axes4 website showing the results for the check. Both PDF/UA and WCAG are fulfilled. Below is more detailed information of the report.

To be really sure that everything is as we intended, we can check our document with a screen reader to see how it interacts with this type of assistive technology.

Testing it with different screen readers

There are many screen reader apps out there and I chose to test with JAWS, NVDA and VoiceOver, as these are the three most popular ones according to the WebAIM Screen Reader User Survey. A great resource on screen reader usage is Your Accessibility Claims Are Wrong, Unless… by Adrian Roselli.

I’m using MacOS Sequoia 15.6 and running Windows 11 on Mac with Parallels. Thanks to this wonderful explainer by Sara Soueidan, I was able to set it up quickly.

Screen reader and browser combinations

Regarding JAWS and NVDA: as I want to keep it as simple as possible, I open the PDF with Microsoft Edge, as it comes pre-installed with Windows 11.

However, some screen readers work better with certain browsers. These are some of the most popular combinations according to the WebAIM Screen Reader User Survey #10, which are also recommended by the IAAP (WAS Body of Knowledge, page 45):

  • JAWS with Chrome
  • NVDA with Firefox (or Chrome)
  • VoiceOver with Safari

JAWS (Version 2025.2508.120) on Windows 11

By pressing H, I’m moving through all the headings in the document, which worked as expected. We can also check the speech output by opening the Speech History via Insert + Spacebar + H.

Screenshot of the Speech History window of JAWS screen reader, with the announced headings highlighted. It shows eleven headings in total.

Next, let’s check the lists by pressing L. It should announce seven lists:

  • Five lists with three items
  • One list with two
  • One list with five items

Screenshot of the Speech History window of JAWS screen reader, with the announced lists highlighted. It shows seven lists in total.

Sweet, this looks good as well! Lastly, let’s check if the links are working as expected by pressing TAB to traverse through the document:

Screenshot of the Speech History window of JAWS screen reader, with the announced links highlighted. It shows six links in total.

Looks like we’re good here! As we formatted our “Send email” hyperlink as a link to send an email straight away, JAWS announces “Send Mail Link” after the accessible name.

NVDA (Version 2025.2) on Windows 11

As before, I’m opening the PDF in Microsoft Edge and press H to traverse through the headings. All of them are announced correctly, let’s have a look at them in the Speech Viewer:

Screenshot of the Speech Viewer window of NVDA screen reader, with the announced headings highlighted. It shows eleven headings in total.

Moving on to the lists by pressing L, they are all recognised and announced correctly. However, NVDA also announces the bullet points here. Which is fine, as the most important thing are lists being announced as lists.

Screenshot of the Speech Viewer window of NVDA screen reader, with the announced lists highlighted. It shows seven lists in total.

When tabbing through the document using TAB, all links are announced as expected. Great, let’s check how this document behaves with VoiceOver.

Screenshot of the Speech Viewer window of NVDA screen reader, with the announced links highlighted. It shows six links in total.

VoiceOver (Version 10) on MacOS Sequoia 15.6

I am opening the document in Preview and use the so called Rotor feature in VoiceOver to get an overview of elements like headings, links, images and many more. Let’s have a look at our heading structure:

“Heading” section of the VoiceOver Rotor feature showing multiple heading levels from one to three.

Everything looks as expected, layers and names are correct! Let’s continue with the links:

“Link” section of the VoiceOver Rotor feature showing six links.

No surprises here either, wonderful. Let’s take a look at the “Images” section:

“Image” section of the VoiceOver Rotor feature showing nothing but the heading.

Nothing is displayed here because we have marked the image as decorative.

Since the lists are not displayed here in Rotor, I navigated directly through the document using VoiceOver, and the lists were announced to me correctly.

Text version of the VoiceOver output saying “content list 3 items”

Wrapping uppermalink

Anyone familiar with Microsoft Word or similar word processing programs should have no problem quickly finding their way around LibreOffice. It is also a small step toward digital sovereignty, moving away from the products of US tech giants.

The example with my resume may not be very complex, but it should contain enough examples for everyday use to quickly and easily create an accessible PDF.

Thanks to axes4, we can test our PDFs without ever having to think about the words “Adobe Acrobat Reader Pro”. If you wan’t to make extra sure, you now know how to check the document with different screen readers too.

Enjoyed this article? You can support us by leaving a tip via Open Collective


Newsletter