So I had the following situation: I am writing my entire software documentation in emacs orgmode, so that I can export it to LaTeX later on. Part of that documentation are quite a lot of tables. The problem is, that by default LaTeX tables (and respectively emacs tables) dont look very good. In this post I will describe my journey of unimaginable pain while going through the process of learning LaTeX in order to gett pretty and uniform tables when exporting orgmode documents to LaTeX. You can find my example files on gitlab. This is primarily meant to be a tutorial and therefore I wont go into every possibility I tried along the way. The technical discussions and tradeoffs (or simply things I could not get to work, even tho they should work) will be discussed the chapter about limitations.
What even does the default look like?
So if we export a table with the default settings, it will look like this:

We can already see the first problem here: Our table is too wide and has no vertical lines. This however can be changed by specifying the columns and the vertical lines:
#+caption: Specifying maximum width and vlines with LaTeX attributes in tabular
#+attr_latex: :align |r|l|p{10cm}|
|-----------+-------------------+----------------------------------------------------------------------------------------|
| Exit code | Type | Meaning |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 0 | External/Internal | Succesfull operation; logical true |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 1 | Internal | Non successfull operation; logical false |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 2 | Internal | A reallly long error message that is long enough to not fit on a single sheet of paper |
|-----------+-------------------+----------------------------------------------------------------------------------------|
Which looks like this when being rendered:

So now our table finally fits on a page and we got vertical lines. There are a number of possible attributes that can be supplied this way, if you want to know more about this, you can find the documentation here. However I think its time to address the obvious: I do not want to paste a bunch of atrributes that I may have to adjust (depending on the table, since we have to specify columns ourselves) for every single table. It is unneccessary work and adds unneccessary lines that could be avoided and dont ever think about changing the way you want your tables to look, because then you can redo the whole process. Its time we find a way to style all of our tables in a way, that they can:
- Introduce automatic linebreaks if the input gets too long
- Look the same for all tables of our choice
- Color individual rows/columns (e.g. make the backgrounf color of the first row grey)
- Handle tables independendly of their column count
- Handle tables spanning multiple pages
Creating a global table style in tabularray
Since it seems like that emacs is rather limited in doing anything like a global table style, it became relatively clear, that I would have to go and do this directly in LaTeX. Luckily the tabularray package for LaTeX is able to do exactly this. The tabularray package also makes it much easier to create more complex LaTeX tables, when compared to the regular tabular enviroment. To add the package simply add the following to your file:
#+LATEX_HEADER: \usepackage{tabularray}
Setup
To start we first need to learn some basics about LaTeX and how emacs handles exporting tables to it. And how we have to adjust this behaviour to our needs. Lets take a look at what the second table looks like once emacs has exported it:
\begin{tabular}{|l|lp{10cm}|r|}
\hline
Exit code & Type & Meaning\\
\hline
0 & External/Internal & Succesfull operation; logical true\\
\hline
1 & Internal & Non successfull operation; logical false\\
\hline
2 & Internal & A reallly long error message that is long enough to not fit on a single sheet of paper\\
\hline
\end{tabular}
As you can see, the table itself defines each cell using an “&” and adding horizontal lines between them. These lines are being manually added by pressing C-c RET in your table. Emacs also used the tabular enviroment (\begin{tabular}) for the table, which is the default table enviroment for LaTeX. You also see that our latex argument got directly passed to the enviroment as an additional argument (this part is called the inner specification of the enviroment). This will come in handy later, once we replaced the tabular enviroment with our own one.
Our table style
First of all: How do we even insert raw LaTeX into orgmode documents? There is a number of different ways to achieve this. You can add LaTeX headers with #+LATEX_HEADER: or insert a single line by using #+LATEX:. If we want to include multiple lines with #+LATEX:, we can also use the #+BEGIN_EXPORT or #+BEGIN_src syntax. We can even use a seperate orgfile in which we store all of our table styles and include it with #+INCLUDE:, which is what we are going to do here. Dump all the LaTeX into a seperate file, so that we dont have to copy it for all of our documents. The advantage of specifying this on a seperate org file (I will call it table_style.org instead of a plain tex file is, that by doing it this way, you can add all packages that you need for your table style in the table_style.org file itself and don’t have to include them in your main file (you can not use the \usepackage command in the body of a document, which is where the included tex file would be included).
First of all, lets create our new table enviroment:
\NewTblrEnviron{globaltbl}
\SetTblrInner[globaltbl]{
}
What this does is, that it creates a completely new table enviroment called globaltbl and every single table that uses this enviroment will inherit all attributes (which we will set in a second) from it. However we will still be able to override all values for each table.
And now lets add some basic attributes to the inner definition:
\NewTblrEnviron{globaltbl}
\SetTblrInner[globaltbl]{
vlines,
hlines,
width = 0.9\linewidth,
rowsep = 4pt,
colsep = 8pt,
colspec={X[t,l]X[t,l]X[t,l]X[t,l]},
}

The hlines and vlines arguments tell tabularray to always draw horizontal and vertical lines between cells, regardless of the appearance of any manually inserted \hline. If the hline option has been given, inserting a \hline into the table will cause tabularray to render a snall gap at the position of the \hline. The width=0.9\linewidth sets the width of the table to 0.9x the width of a single line. The rowsep and colsep attributes control how much space between your text input and your hlines / vlines you have.
If you want a deeper understanding of the colspec attribute please go and look up cell alignemts of the tabularray package. For now all you need to know is, that this defines four columns for our table style and each column will align its text at the top left of the cell (indicated by t and l in the specifications for each column). Since we use the so called X column here, we also get automatic linebreaks in our table. If we dont want this, we would have to use the primitive Q column instead (replace all occurences of X with a Q in the colspec).
Changing behaviour of single rows, columns, cells and even more
So we were able to set the width of our table, but what if I want to e.g. color the first row grey and all following uneven rows too, but in a different shade? Dont worry, all of this is very easy. We simply define these rows in our table style and are good to go:
row{1} = {
bg=grey9,
fg=white,
font=\bfseries,
halign=c
},
row{odd[3]} = {
bg=grey5
}
The same principle can be applied to columns, single cells and even single hlines and vlines:
row{odd[3]} = {bg=gray9}, %% Change bg color of all odd rows starting with the third row
column{2} = {halign=r}, %%align the second column to the right
cell{4}{3} = {bg=red}, %% Change the bg color of the cell in the 4th row and third column
hline{3}={dotted, red}, %%Change the way the third horizontal line gets rendered
We can also specify ranges of columns (etc).
column{1-2} = {mode=text} %%changes the mode of the first two columns
column{Z} = {mode=text} %%Change the mode of the last column
column{3-Y} = {mode=math} %%changes the mode of each column except the first two and the last column
Using the table style
So now that we know how to create our table style, how do we use it inside our org files? Sadly it seems like there is no way to directly set the enviroment of our tables to our custom enviroment (if you know a better solution please tell me), however there are a few tricks we can use. Using the \renewenviroment command from LaTeX, we can tell the LaTeX engine to replace the enviroment of all following tables to another enviroment (it can be used for more than tables, but we only care about tables here). Since the command only affects following enviroments, we can also use the command multiple times in a file to cycle between multiple layouts. Lets assume we have defined the table enviroments globaltbl and nonglobaltbl, then we could use the corresponding styles like the following:
#+LATEX: \renewenvironment{tabular}{\begin{globaltbl}}{\end{globaltbl}}
.... table 1 ....
.... table 2 ....
#+LATEX: \renewenvironment{tabular}{\begin{nonglobaltbl}}{\end{nonglobaltbl}}
.... table 3 ....
#+LATEX: \renewenvironment{tabular}{\begin{globaltbl}}{\end{globaltbl}}
.... table 4 ....
Overriding preset values
So now that we have seen how to pre set values, how do we override them for a single table? Well, we just have to pass our table the corresponding arguemnts to the table. So if I as example want to set the color of a single cell in my table (lets say the top left cell) to red. Well, I simply add
+attr_latex: :align cell{1}{1} = {bg=red}
to my table and Im good to go. Everything that we can specify in the inner definition of our enviroment, can be overwritten this way. Using this we can go absolutely wild with our tables, without affecting any other tables:
#+attr_latex: :align row{2}={bg=blue,fg=white}, row{1}={fg=green, halign=l}, width=0.5\linewidth, hline{3}={text=<<<<<<<<<<, red}
#+caption: Its always possible to override absolutely anything, while still using nonglobaltbl
|-----------+-------------------+----------------------------------------------------------------------------------------|
| Exit code | Type | Meaning |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 0 | External/Internal | Succesfull operation; logical true |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 1 | Internal | Non successfull operation; logical false |
|-----------+-------------------+----------------------------------------------------------------------------------------|
| 2 | Internal | A reallly long error message that is long enough to not fit on a single sheet of paper |
|-----------+-------------------+----------------------------------------------------------------------------------------|

Overriding existing enviroments
Now lets say, what happens if our table suddenly becomes really really big and is longer than it is possible to vertically fit onto a single page? Well, lucky for us, tabularray got us covered by providing the longbtlr enviroment for us to use for this case. We can simply override its specifications:
\SetTblrInner[longtblr]{
%%specifications as we are used to
}
So whats about multirow/-column cells?
First up: As far as I’m concerned, there is no way to create multicolumn or multirow cells inside emacs, the way it is possible with LaTeX, without having to dig very deep into the latex-export-backend of orgmode. This is 100% out of my skillrange and it is something I dont need (yet). If you really need this, you will have to use LaTeX directly. If you really need the math functionalities, but also multirow­column cells, and have so many of them, that you cant type them by hand anymore, than its probably time to automate the creation of your tables in any other way.
The only way it is possible to mimick multirow/-column cells is by controlling where hlines and vlines are being drawn. The easiest way to mimic multirow columns is to turn off hlines and manually insert the lines in the orgmode table by pressing C-C RET inside your table, as it can be seen here:



Using the default specifications for a table
If you want to use an empty enviroment that has no specifications (which means it will look like the default tabularray table), simply define a new enviroment, without setting its inner specification:
\NewTblrEnviron{deftblr}
Limitations
One limitation is, that with the current approach of using the \renewenviroment command, you will no longer be able to use your default export enviroment later in your file. This might not be a problem when working alone, but it might become a problem when collaborating with other people. Sadly I was not able to figure out if there is any other way to reliably change the enviroment of a table (or respectively all tables in the document). However I was also never able to change the enviroment of a single table to tblr (the name used for tabularray in emacs) the way it has been decribed here. It is also not possible to embed tables directly into the text. This can only be achieved by typesetting the table directly in LaTeX and using tabularrays talltblr enviroment.
Conclusion
I would say that jumping through the hoops to create some good looking table style is really worth it. First of all its way better than manually pasting the same 20 arguments for every table. It allows you to use multiple styles in the same document and if you need extended functionality of the tabularray package like multirow/-column cells or the talltblr enviroment to embed tables directly into your text, then it is pretty easy to do this, since new styles can be created on the fly and tabularray is relatively easy to use.


Everything you say is right, but at least for now this is not that much of a problem. My workplace is quite small and teams are usually the size of about 5 people. We also don’t have any strict guidelines for anything and there isnt that much standardization. Two of my coworkers use Lyx for their documents and documentation, while me and another person prefer orgmode (he started using it after I showed him my documentation I worked out in orgmode). Since my other colleagues use Lyx (which is just a GUI for LaTeX), it actually is not that much of a problem, since they can simply include my files. Alternatively it would also be possible to add the rendered pdfs together, however thats kind of a dirty way.
Would it be better if we used a more standardised solution for writing documentation? Absolutely, but currently we dont have that and I am not in a position to change this (and I also like emacs enough, that I dont want to leave my ecosystem).