Setup Used

LaTeX is used by many for the creation of PDF documents. Here we explore how to make such PDFs documents accessible. TeXLive 2026 is utilized and the document is compiled via lualatex filename.tex in order turn filename.tex into a PDF. Of course it is easier to configure an IDE (Integrated Development Environment) such as TeXstudio to save typing. It is possible to use TeXLive 2025, but you will need to utilize the development branch lualatex-dev filename.tex in order to create a PDF. Earlier versions of TeXLive may not work. Additionally, only TeXLive has been tested, although it is likely that MiKTeX or other recent distributions of LaTeX would work.

For some things to work properly, you will need to make sure that your IDE includes –shell-escape flag to lualatex.exe. This allows external programs to be executed and allows lualatex.ext to run python.exe or even TikZ if you are using the added external library for enhanced speed. For example, you might run lualatex –shell-escape my_document.tex in the command line or configure the IDE. There are other reasons for shell escape. Keep using LaTeX and you’ll find them! This can be dangerous as it allows LaTeX to execute any command line script on your machine. Code from an external source can be dangerous!

Files used in this tutorial include

Document Structure

There are two different paths which LaTeX can follow for including MathML in PDF documents. One generates a PDF which uses structure elements to contain MathML. The other includes MathML in embedded and associated files. This page covers the former.

A basic LaTeX file might look like the following.

% ------------------------------------------------------------
%   Document Preamble Settings for Tagged, Accessible PDF
% ------------------------------------------------------------

% Modern LaTeX document options and metadata (requires TeX Live 2026+ and LuaLaTeX)
\DocumentMetadata{
	pdfversion = 2.0,        % Use PDF 2.0 for enhanced features and compatibility
	lang       = en-US,      % Specify main document language (improves accessibility)
	pdfstandard=ua-2,        % Enable PDF/UA-2 conformance for universal accessibility
	tagging    = on,         % Activate structural tagging of document elements
	% Uncomment below for custom math tagging and alternate modules if needed:
	%tagging-setup = {math/setup=mathml-AF, extra-modules={verbatim-af}}
	tagging-setup = {math/setup={mathml-SE}, % Configure Math as Structure Elements
		math/alt/use = true,    % Embed alternative LaTeX source in math (impacts accessibility)
		extra-modules = {verbatim-af} % Add module for verbatim environments
	}
}

\documentclass{article} % Or some other class file

% ========== Packages for extra features ==========
\usepackage{amsmath,amsthm}       % For better math typesetting
\usepackage[colorlinks]{hyperref}      % For clickable links and PDF bookmarks
\usepackage{unicode-math}  % Maps LaTeX commands for mathematical characters to the Unicode Mathematical Alphanumeric Symbols block.
\usepackage{graphicx}      % For including images
\pagestyle{empty}          % (Optional) Removes page numbers (nicer for examples)

\usepackage{authblk}		% Helps with author names and affiliations

\newtheorem{theorem}{Theorem}[section]  % Numbering resets when a section changes
\newtheorem{corollary}{Corollary}[theorem]  % Numbering resets when a new theorem happens
\newtheorem{lemma}[theorem]{Lemma}  % Uses the same counter as Theorem
\newtheorem{definition}{Definition}  % Uses the same counter as Theorem
\newtheorem{example}{Example}  % Uses the same counter as Theorem

\usepackage{tikz}
\usetikzlibrary{positioning}

\usepackage[executable=python.exe]{pyluatex}  % Because I'm using Python

% Other Packages or commands as needed

\begin{document}
   \title{Cool Title}
   \date{28 July 2026}
   \author{Your Name} 
   \affil{Where are you?}

   \maketitle

   % Your awesome document using \chapter{}, \section{}, etc as needed
\end{document}

Preamble

The following code block is placed before the typical \documentclass{article}. A pdfversion of 2.0 specifies that the more modern version of PDF documents is being utilized allowing better accessibility features. The lang specifies the English language is utilized. The standard pdfstandard line indicates that PDF/UA-2 standard is being used. The line tagging=on indicates that sections, lists, math, etc. are tagged as specified through tagging-setup line. The tagging setup uses structural elements, allows alternative LaTeX source in math, and add a module for verbatim environments.

% ------------------------------------------------------------
%   Document Preamble Settings for Tagged, Accessible PDF
% ------------------------------------------------------------

% Modern LaTeX document options and metadata (requires TeX Live 2026+ and LuaLaTeX)
\DocumentMetadata{
	pdfversion = 2.0,        % Use PDF 2.0 for enhanced features and compatibility
	lang       = en-US,      % Specify main document language (improves accessibility)
	pdfstandard=ua-2,        % Enable PDF/UA-2 conformance for universal accessibility
	tagging    = on,         % Activate structural tagging of document elements
	% Uncomment below for custom math tagging and alternate modules if needed:
	%tagging-setup = {math/setup=mathml-AF, extra-modules={verbatim-af}}
	tagging-setup = {math/setup={mathml-SE}, % Configure Math as Structure Elements
		math/alt/use = true,    % Embed alternative LaTeX source in math (impacts accessibility)
		extra-modules = {verbatim-af} % Add module for verbatim environments
	}
}

If you wish to have a PDF which includes MathML inside embedded and associated files, then uncomment the line containing tagging-setup = {math/setup=mathml-AF, extra-modules={verbatim-af}} and comment the next three lines.

We don’t explicitly include the tagpdf package because tagging = on will load the package for us.

Some Nice Packages

There are an amazing number of interesting LaTeX packages which can be utilized. Here we use several as shown above. in particular, pyluatex adds Python capabilities to the document, tikz is great for creating custom diagrams, authbolk is used to indicate author data, graphicx is the standard for including images such as *.PNG or *.PDF. The libraries amsmath and amsthm are nice additions and allow more flexible mathematical structures and theorems. Finally, hyerref allows nice hyperlinks and bookmarks and unicode-math allows usage of Unicode.

Best Practices

Sections, Theorems, Lists, Math, Etc.

Make sure that you use \chapter{Some Name}, \section{Some Name}, etc to correctly tag chapters and sections in the PDF document. Paragraphs are automatically tagged as paragraphs.

Math environments which also include the standard environment such as $x^2$ as well as the more interesting environments such as \begin{equation}\end{equation} or \begin{align} .. \end{align} are tagged as mathematics.

Lists such as itemize, enumerate, or description are tagged as lists. Links using \href{} or \url{} are tagged as links.

Use \begin{theorem}\end{theorem} to create appropriately tagged theorem environments (or definitions, examples, etc.). The amsmath and amsthm packages help with creation of such structures. Do not use \textbf{Theorem} as this will not be properly tagged. But you could create custom tags.

Custom tagging

However, custom content such as your own environments or macros are not automatically tagged. Additionaly raw boxes or some low-level content such as \hbox{} are not tagged. This will need manual tagging using \tagstructbegin and \tagstructend to ensure it is correctly identified as a paragraph. For example, the following code snippet would tag several lines as a paragraph.

%--- Manual structure tagging commands (from tagpdf package) ---
\tagstructbegin{tag=P}         % Begin a new structure element (a paragraph, "P")
\tagmcbegin{tag=P}             % Begin marked content for the same paragraph
This paragraph is manually wrapped with \texttt{\string\tagstructbegin} and \texttt{\string\tagstructend} commands to ensure it is correctly identified as a paragraph structure element in the output PDF's structure tree.
\tagmcend                     % Ends marked content
\tagstructend                 % Ends the structure element
%--- End manual tagging ---

Note that since tagging=on is inside the \DocumentMetaData{…}, we don’t explicitly include the tagpdf package.

There are a lot of different tags available. Rather that \tagstructbegin{tag=P} where P represents paragraph, you can use Part is a high level method for grouping multiple chapters or sections together. Aside is used for blocks of content that are separate from the main flow, such as sidebars or callouts. Headings such as H1, H2, through H6 can be used with H a generic heading tag. You can specify a title using Title. Lists, tables, and figures are also possible and so much more. Searching online will be a good idea for these as it gets more and more involved. When possible, let LaTeX tag as many things as possible for you.

Tables

Tables need to have a header row. A minimal working example would be

\tagpdfsetup{table/header-rows={1}} % This identifies the header row as the first row
\begin{tabular}{|l|c|c|}
	\hline
	Fruit & Calories & Fiber (g) \\
	\hline
	Apple  & 52       & 2.4 \\
	Banana & 89       & 2.6 \\
	Orange & 47       & 2.4 \\
	\hline
\end{tabular}

Of course, you might have two or more rows. I decided the table should be centered.

\begin{center}
	\tagpdfsetup{table/header-rows={1,2}} % This identifies the header rows as the first two rows
	\begin{tabular}{l|r}
		\multicolumn{2}{c}{Example}\\
		Name & Value\\
		This & 11 \\
		That & 2
	\end{tabular}
\end{center}

Even better would be a table with a caption and a label which can be cross referenced using the standard LaTeX command \ref{tab-sec-slope}.

\begin{table}[h]
	\centering
	\caption{Slopes of three different secant lines.}\label{tab-sec-slope}
	\tagpdfsetup{table/header-rows={1}}  % This identifies the header row as the first row
	\begin{tabular}{c|c}
		\hline
		$x$ & $m_{sec} = \dfrac{f(x)-f(a)}{x-a}$ \\\hline
		$-\dfrac{3}{2}$ & $-\dfrac{13}{4}$ \\
		$\dfrac{1}{2}$ & $\dfrac{5}{4}$ \\
		$\dfrac{1}{2}$ & $\dfrac{17}{4}$ 
	\end{tabular}
\end{table}

It is also possible to specify one or more columns. For example, use the following code to indicate

\begin{center}
    % Define the structural header matrix
    \tagpdfsetup{
        table/header-rows={1,2},       % Rows 1 & 2 contain structural time headers
        table/header-columns={1,2}     % Columns 1 & 2 contain product categorization headers
    }
    
    \begin{tabular}{ll|cc}
        % --- ROW 1 (Header Row) ---
        % Cells 1 & 2 are empty corner headers. Cells 3 & 4 span under a 2026 grouping.
        & & \multicolumn{2}{c}{\textbf{Fiscal Year 2026}} \\ 
        
        % --- ROW 2 (Header Row) ---
        % Cells 1 & 2 finish the corner. Cells 3 & 4 provide the sub-headers.
        \textbf{Division} & \textbf{Product} & \textbf{Q1 Target} & \textbf{Q2 Target} \\ \hline
        
        % --- ROW 3 (Data Row) ---
        % Columns 1 & 2 are treated as row headers (<TH>). Columns 3 & 4 are data (<TD>).
        Software & Cloud SaaS & \$50k & \$65k \\ 
        
        % --- ROW 4 (Data Row) ---
        Software & On-Premise & \$20k & \$15k \\ \hline
        
        % --- ROW 5 (Data Row) ---
        Hardware & Servers    & \$80k & \$95k 
    \end{tabular}
\end{center}

Figures

Who doesn’t like figures? We always need to include alt-text with figures, whether they are simply images included or a true figure.

A basic figure block with a label which can be references using Figure~\ref{fig-sec-tan} (note that the “~” after the word Figure is optional, but indicates a non-breaking space so that the word Figure and the figure number are not separated at the end of a line) is shown below. The important part is the use of alt={The graph…} within the \includegraphics command which specifies the alternative text for the figure. Note that a minimal figure can be generated by simply using the \includegraphics command with the alternative text.

% --- Figure with embedded alternative text (accessibility for images) ---
\begin{figure}[h]
	\centering
	% Use the 'alt' key directly within \includegraphics
	\includegraphics[width=\linewidth, alt={The graph of $f(x)$ with its tangent line and several secant lines.}]{secant_tangent_lines_by_hand.png}
	\caption{The graph of $f(x)$ with its tangent line and several secant lines.}\label{fig-sec-tan}
\end{figure}

For a purely decorative image, use \includegraphics[artifact]{image.png}.

For a picture of a unicode character, use \includegraphics[actualtext=B]{image.png} to indicate that image.png represents the letter “B”.

Python

It is possible to include Python generated images. The following code will generate a damped sign wave, save the image under the name secant-tangent-python.pdf. This is particularly nice since the code which created the image is embedded within the document.

Be sure to include \usepackage[executable=python.exe]{pyluatex} % Because I’m using Python to load the pyluatex package. The optional argument executable=python.exe is used to specify which Python interpreter is to be run. This is particularly useful when there are multiple Python environments.

For some things to work properly, you will need to make sure that your IDE includes –shell-escape flag to lualatex.exe. This allows external programs to be executed and allows lualatex.ext to run python.exe. For example, you might run lualatex –shell-escape my_document.tex in the command line or configure the IDE. This can be dangerous as it allows LaTeX to execute any command line script on your machine. Code from an external source can be dangerous!

\begin{python}
import numpy as np 
import matplotlib.pyplot as plt 

x = np.linspace(-4, 6, 1000) 
f = -x**3 + 4*x**2 - x - 6 

l1 = -13*x/4 + 3 
l2 = 5*x/4 - 15/4 
l3 = 15*x/4 - 15/2 
l4 = 17*x/4 - 33/4 

fig, ax = plt.subplots(figsize=(8, 3)) 

ax.plot(x, f, color='blue', linewidth=2, label='f(x) = -x^3+4x^2-x-6') 
ax.plot(x, l1, '--', color='red', linewidth=1.5, label='y = -13x/4 + 3') 
ax.plot(x, l2, '--', color='green', linewidth=1.5, label='y = 5x/4 - 15/4') 
ax.plot(x, l3, '--', color='brown', linewidth=1.5, label='y = 15x/4 - 15/2') 
ax.plot(x, l4, color='black', linewidth=1.5, label='y = 17x/4 - 33/4') 

x0, y0 = 3/2, -15/8 
ax.plot(x0, y0, 'ko', markersize=6) 
ax.plot(-3/2, 63/8, 'ro') 
ax.plot(-1/2, -35/8, 'go', markersize=6) 
ax.plot(1/2, -45/8, 'o', color = 'brown', markersize=6) 

ax.set_xlim(x.min(), x.max()) 
ax.set_ylim(-10, 10) 
ax.axhline(0, color='gray', lw=0.6) 
ax.axvline(0, color='gray', lw=0.6) 
ax.set_xlabel('x')
ax.set_ylabel('y') 
ax.legend(loc='best', fontsize=9) 
ax.grid(alpha=0.3)

fig.savefig('secant-tangent-python.pdf')
plt.close()
\end{python}

The next few lines of code will include the image using the ideas above.

% Display the figure.
\begin{figure}[ht]
	\centering
	\includegraphics[width=\linewidth, alt={The graph of $f(x)$ with its tangent line and several secant lines.}]{secant-tangent-python.pdf}
	\caption{The graph of $f(x)$ with its tangent line and several secant lines. Generated by Python embedded in the \LaTeX\ document.}\label{fig-sec-tan-2}
\end{figure}
Tikz

TikZ is a common package for generating images. To make them accessible, you still alt-text and can include the optional caption and a label when wrapping with a figure block. The following code snippet illustrates how to reference a TikZ figure. Note that within the \begin{tikzpicture} block, there is {alt=TikZ figure. which generates alternative text. A caption and referenceable label are done in the typical manner.

For some things to work properly, you will need to make sure that your IDE includes –shell-escape flag to lualatex.exe. This allows external programs to be executed and allows TikZ to use the added external library for enhanced speed. The TikZ library will create and store TikZ drawings as PDF files. Seek the documentation for more information about externalization as it is not covered on this page. You will run lualatex –shell-escape my_document.tex in the command line or configure the IDE. This can be dangerous as it allows LaTeX to execute any command line script on your machine. Code from an external source can be dangerous!

Often people utilize TikZ to generate figures. See Figure~\ref{fig-myTikZ}.

\begin{figure}[h]
	\centering
	\begin{tikzpicture}[
		roundnode/.style={circle, draw=green!60, fill=green!5, very thick, minimum size=7mm},
		squarednode/.style={rectangle, draw=red!60, fill=red!5, very thick, minimum size=5mm},
		]{alt=TikZ figure.}
		%Nodes
		\node[squarednode]      (maintopic)                              {2};
		\node[roundnode]        (uppercircle)       [above=of maintopic] {1};
		\node[squarednode]      (rightsquare)       [right=of maintopic] {3};
		\node[roundnode]        (lowercircle)       [below=of maintopic] {4};
		
		%Lines
		\draw[->] (uppercircle.south) -- (maintopic.north);
		\draw[->] (maintopic.east) -- (rightsquare.west);
		\draw[->] (rightsquare.south) .. controls +(down:7mm) and +(right:7mm) .. (lowercircle.east);
	\end{tikzpicture}
	\caption{My nice TikZ figure.}\label{fig-myTikZ}
\end{figure}

References

Below are some links for more information.