texlive[62328] Master/texmf-dist: tabularray (1mar22)

commits+karl at tug.org commits+karl at tug.org
Tue Mar 1 22:53:06 CET 2022


Revision: 62328
          http://tug.org/svn/texlive?view=revision&revision=62328
Author:   karl
Date:     2022-03-01 22:53:05 +0100 (Tue, 01 Mar 2022)
Log Message:
-----------
tabularray (1mar22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.pdf
    trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.tex
    trunk/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty
    trunk/Master/texmf-dist/tex/latex/tabularray/tabularray.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/tabularray/README.txt

Removed Paths:
-------------
    trunk/Master/texmf-dist/doc/latex/tabularray/README

Deleted: trunk/Master/texmf-dist/doc/latex/tabularray/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/tabularray/README	2022-03-01 21:52:45 UTC (rev 62327)
+++ trunk/Master/texmf-dist/doc/latex/tabularray/README	2022-03-01 21:53:05 UTC (rev 62328)
@@ -1,6 +0,0 @@
-Package: Typeset tabulars and arrays with LaTeX3
-Author: Jianrui Lyu <tolvjr at 163.com>
-CTAN: https://ctan.org/pkg/tabularray
-Repository: https://github.com/lvjr/tabularray
-Repository: https://bitbucket.org/lvjr/tabularray
-License: The LaTeX Project Public License 1.3

Added: trunk/Master/texmf-dist/doc/latex/tabularray/README.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/tabularray/README.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/tabularray/README.txt	2022-03-01 21:53:05 UTC (rev 62328)
@@ -0,0 +1,6 @@
+Package: Typeset tabulars and arrays with LaTeX3
+Copyright: 2021-2022 (c) Jianrui Lyu <tolvjr at 163.com>
+CTAN: https://ctan.org/pkg/tabularray
+Repository: https://github.com/lvjr/tabularray
+Repository: https://bitbucket.org/lvjr/tabularray
+License: The LaTeX Project Public License 1.3


Property changes on: trunk/Master/texmf-dist/doc/latex/tabularray/README.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.tex	2022-03-01 21:52:45 UTC (rev 62327)
+++ trunk/Master/texmf-dist/doc/latex/tabularray/tabularray.tex	2022-03-01 21:53:05 UTC (rev 62328)
@@ -1,15 +1,19 @@
 % -*- coding: utf-8 -*-
 % !TEX program = lualatex
 \documentclass[oneside]{book}
-\newcommand*{\myversion}{2021Q}
+\newcommand*{\myversion}{2022A}
 \newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi}
 
 \usepackage[a4paper,margin=2.5cm]{geometry}
 
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{4pt plus 1pt minus 1pt}
+
 \usepackage{codehigh} % https://ctan.org/pkg/codehigh
 \usepackage{tabularray}
 \usepackage{array,multirow,amsmath}
 \usepackage{chemmacros,environ}
+\usepackage{enumitem}
 
 \usepackage[firstpage=true]{background}
 \backgroundsetup{contents={}}
@@ -84,8 +88,8 @@
   %color = black,
   contents = {
     \begin{tblr}{
-      width = \paperwidth, columns = {1}, rows= {4em},
-      cell{odd}{odd} = {gray9}, cell{even}{even} = {gray9},
+      width = \paperwidth, columns = {1}, rows= {4em, gray9},
+      hlines = {2.8pt,white}, vlines = {2.8pt,white},
     }
       & & & & & & & & & & & & & & \\
       & & & & & & & & & & & & & & \\
@@ -105,8 +109,6 @@
       & & & & & & & & & & & & & & \\
       & & & & & & & & & & & & & & \\
       & & & & & & & & & & & & & & \\
-      & & & & & & & & & & & & & & \\
-      & & & & & & & & & & & & & & \\
     \end{tblr}
   }
 }
@@ -154,6 +156,13 @@
 
 \chapter{Overview of Features}
 
+Before using \verb!tabularray! package, it is better to know how to typeset simple text and
+math tables with traditional \verb!tabular!, \verb!tabularx! and \verb!array! environments,
+because we will compare \verb!tblr! environment from \verb!tabularray! package with these
+environments. You may read web pages on LaTeX tables on
+\href{https://www.learnlatex.org/en/lesson-08}{LearnLaTeX} and
+\href{https://www.overleaf.com/learn/latex/Tables}{Overleaf} first.
+
 \section{Vertical Space}
 
 After loading \verb!tabularray! package in the preamble,
@@ -185,7 +194,7 @@
 \end{tblr}
 \end{demohigh}
 
-You may notice that there is extra space above and below the table rows with \verb!tblr! envirenment.
+You may notice that there is extra space above and below the table rows with \verb!tblr! environment.
 This space makes the table look better.
 If you don't like it, you could use \verb!\SetTblrInner! command:
 
@@ -202,7 +211,7 @@
 \end{tblr}
 \end{demohigh} 
 
-But in many cases, this rowsep is useful:
+But in many cases, this \verb!rowsep! is useful:
 
 \begin{demo}
 $\begin{array}{rrr}
@@ -367,7 +376,7 @@
      & \multicolumn{2}{c|}{2 Columns}
                  & \multicolumn{2}{c|}{\multirow{2}{*}{2 Rows 2 Columns}} \\
 \cline{2-3}
-     & 2-2 & 2-3 & \multicolumn{2}{c|}{} \\
+     & 2-2 & 2-3 & \multicolumn{2}{c|}{} \\
 \hline
  3-1 & 3-2 & 3-3 & 3-4 & 3-5 \\
 \hline
@@ -387,7 +396,7 @@
      & \SetCell[c=2]{c} 2 Columns
            &     & \SetCell[r=2,c=2]{c} 2 Rows 2 Columns & \\
 \hline
-     & 2-2 & 2-3 &     &     \\
+     & 2-2 & 2-3 &     &     \\
 \hline
  3-1 & 3-2 & 3-3 & 3-4 & 3-5 \\
 \hline
@@ -484,7 +493,7 @@
 and vertical alignment in \verb!rowspec!, respectively.
 
 Inside \verb!rowspec!, \verb!|! is the hline type.
-Therefore we need not to write \verb!\hline! commnad, which makes table code cleaner.
+Therefore we need not to write \verb!\hline! command, which makes table code cleaner.
 
 \section{Hlines and Vlines}
 
@@ -505,7 +514,8 @@
 \section{Colorful Tables}
 
 To add colors to your tables, you need to load \verb!xcolor! package first.
-\verb!Tabularray! package will also load \verb!ninecolors! package for proper color contrast.
+\verb!Tabularray! package will also load
+\href{https://ctan.org/pkg/ninecolors}{\texttt{ninecolors}} package for proper color contrast.
 First you can specify background option for \verb!Q! rows/columns inside \verb!rowspec!/\verb!colspec!:
 
 \begin{demohigh}
@@ -564,6 +574,7 @@
 \end{demohigh}
 
 \chapter{Basic Interfaces}
+\label{chap:basic}
 
 \section{Old and New Interfaces}
 
@@ -583,9 +594,11 @@
 ]{verb}
   Old Interfaces                                 & New Interfaces          \\
   \verb!\SetHlines!                              & \K{hlines}              \\
-  \verb!\SetHline!, \verb!\hline!, \verb!\cline! & \K{hline}, \K{rowspec}  \\
+  \verb!\SetHline!, \verb!\hline!, \verb!\hborder!, \verb!\cline!
+                                                 & \K{hline}, \K{hborder}, \K{rowspec}  \\
   \verb!\SetVlines!                              & \K{vlines}              \\
-  \verb!\SetVline!, \verb!\vline!, \verb!\rline! & \K{vline}, \K{colspec}  \\
+  \verb!\SetVline!, \verb!\vline!, \verb!\vborder!, \verb!\rline!
+                                                 & \K{vline}, \K{vborder}, \K{colspec}  \\
   \verb!\SetCells!                               & \K{cells}               \\
   \verb!\SetCell!                                & \K{cell}                \\
   \verb!\SetRows!                                & \K{rows}                \\
@@ -611,10 +624,6 @@
   \K{leftpos}          & crossing or trimming position at the left side  & \V{1} \\
   \K{rightpos}         & crossing or trimming position at the right side & \V{1} \\
   \K{endpos}           & adjust leftpos/rightpos for only the leftmost/rightmost column & \V{false} \\
-  \K{abovespace}       & set \V{belowsep} of previous row (see Table \ref{key:row}) & \V{2pt} \\
-  \K{belowspace}       & set \V{abovesep} of current row (see Table \ref{key:row}) & \V{2pt} \\
-  \K{abovespace+}      & increase \V{belowsep} of previous row & \None \\
-  \K{belowspace+}      & increase \V{abovesep} of current row  & \None \\
 \end{spectblr}
 \vspace{-2em}
 \begin{spectblr}[
@@ -720,7 +729,7 @@
 \end{tblr}
 \end{demohigh}
 
-You can use \verb!X!, \verb!Y!, \verb!Z! to denote the last three childs, respectively.
+You can use \verb!X!, \verb!Y!, \verb!Z! to denote the last three children, respectively.
 It is especially useful when you are writing long tables:
 
 \begin{demohigh}
@@ -892,6 +901,42 @@
 are similar to those of \verb!\hline!, \verb!\cline!, \verb!\SetHline!, \verb!\SetHlines!, respectively.
 But normally you don't need to use them.
 
+\section{Hborders and Vborders}
+
+Options \verb!hborder{i}! and \verb!vborder{j}! are similar to \verb!hline{i}! and \verb!vline{j}!,
+respectively, but they hold border specifications not related to one specific hline and vline.
+All available keys for \verb!hborder{i}! and \verb!vborder{j}! are described in
+Table~\ref{key:hborder} and Table~\ref{key:vborder}.
+
+\begin{spectblr}[
+  caption = {Keys for Hborders},
+  label = {key:hborder},
+]{}
+  Key & Description and Values & Initial Value \\
+  \K{pagebreak}   & pagebreak at this position: \V{yes}, \V{no} or \V{auto}
+                    (See Chapter~\ref{chap:long}) & \V{auto} \\
+  \K{abovespace}  & set \V{belowsep} of previous row (see Table \ref{key:row}) & \V{2pt} \\
+  \K{belowspace}  & set \V{abovesep} of current row (see Table \ref{key:row}) & \V{2pt} \\
+  \K{abovespace+} & increase \V{belowsep} of previous row & \None \\
+  \K{belowspace+} & increase \V{abovesep} of current row  & \None \\
+\end{spectblr}
+\vspace{-2em}
+\begin{spectblr}[
+  caption = {Keys for Vborders},
+  label = {key:vborder},
+]{}
+  Key & Description and Values & Initial Value \\
+  \K{leftspace}   & set \V{rightsep} of previous column (see Table \ref{key:column}) & \V{6pt} \\
+  \K{rightspace}  & set \V{leftsep} of current column (see Table \ref{key:column}) & \V{6pt} \\
+  \K{leftspace+}  & increase \V{rightsep} of previous column & \None \\
+  \K{rightspace+} & increase \V{leftsep} of current column  & \None \\
+\end{spectblr}
+
+Furthermore, table command \verb!\hborder{<specs>}! at the beginning of row \verb!i!
+is the same as table option \verb!hborder{i}={<specs>}!,
+and table command \verb!\vborder{<specs>}! at the beginning of column \verb!j!
+is the same as table option \verb!vborder{j}={<specs>}!.
+
 \section{Cells and Spancells}
 
 All available keys for cells are described in Table \ref{key:cell} and Table \ref{key:cellspan}.
@@ -904,7 +949,7 @@
   Key & Description and Values & Initial Value \\
   \underline{\K{halign}}
     & horizontal alignment: \V{l} (left), \V{c} (center), \V{r} (right) or \V{j} (justify)
-    & \V{l} \\
+    & \V{j} \\
   \underline{\K{valign}}
     & vertical alignment: \V{t} (top), \V{m} (middle), \V{b} (bottom),
       \V{h} (head) or \V{f} (foot)
@@ -1040,8 +1085,8 @@
 ]{verb}
   Key & Description and Values & Initial Value \\
   \underline{\K{halign}}
-    & horizontal alignment: \V{l} (left), \V{c} (center), or \V{r} (right)
-    & \V{l} \\
+    & horizontal alignment: \V{l} (left), \V{c} (center), \V{r} (right) or \V{j} (justify)
+    & \V{j} \\
   \underline{\K{valign}}
     & vertical alignment: \V{t} (top), \V{m} (middle), \V{b} (bottom),
       \V{h} (head) or \V{f} (foot)
@@ -1071,8 +1116,8 @@
 ]{verb}
   Key & Description and Values & Initial Value \\
   \underline{\K{halign}}
-    & horizontal alignment: \V{l} (left), \V{c} (center), or \V{r} (right)
-    & \V{l} \\
+    & horizontal alignment: \V{l} (left), \V{c} (center), \V{r} (right) or \V{j} (justify)
+    & \V{j} \\
   \underline{\K{valign}}
     & vertical alignment: \V{t} (top), \V{m} (middle), \V{b} (bottom),
       \V{h} (head) or \V{f} (foot)
@@ -1220,7 +1265,7 @@
 
 \subsection{Colspec and Width}
 
-Option \verb!width! are for setting the width of the table with extendable columns.
+Option \verb!width! is for setting the width of the table with extendable columns.
 The following example demonstrates the usage of \verb!width! option.
 \nopagebreak
 \begin{demohigh}
@@ -1302,13 +1347,31 @@
 \chapter{Extra Interfaces}
 \label{chap:extra}
 
-\section{Table Specifications}
+In general, \verb!tblr! environment can accepts both inner and outer specifications:
 
-All available keys for the whole table are described in Table \ref{key:table}.
+\begin{codehigh}
+\begin{tblr}[<outer specs>]{<inner specs>}
+  <table body>
+\end{tblr}
+\end{codehigh}
 
+\textbf{Inner specifications} are all specifications written in the \underline{mandatory} argument
+of \verb!tblr! environment, which include new interfaces described in Chapter \ref{chap:basic}.
+
+\textbf{Outer specifications} are all specifications written in the \underline{optional} argument
+of \verb!tblr! environment, most of which are used for long tables (see Chapter \ref{chap:long}).
+
+You can use \verb!\SetTblrInner! and \verb!\SetTblrOuter! commands
+to set default inner and outer specifications of tables, respectively.
+
+\section{Inner Specifications}
+
+In addition to new interfaces in Chapter \ref{chap:basic},
+there are several inner specifications which are described in Table~\ref{key:inner}.
+
 \begin{spectblr}[
-  caption = {Keys for the Whole Table},
-  label = {key:table},
+  caption = {Keys for Inner Specifications},
+  label = {key:inner},
 ]{}
   Key & Description and Values & Initial Value \\
   \K{rulesep} & space between two hlines or vlines & \V{2pt} \\
@@ -1321,8 +1384,12 @@
   \K{colsep} & set horizontal space to both sides of every column & \V{6pt} \\
   \K{hspan} & horizontal span algorithm: \V{default}, \V{even}, or \V{minimal} & \V{default} \\
   \K{vspan} & vertical span algorithm: \V{default} or \V{even} & \V{default} \\
+  \K{verb} & you need this key to use verb commands & \None \\
+  \K{baseline} & set the baseline of the table & \V{m} \\
 \end{spectblr}
 
+\subsection{Space between Double Rules}
+
 The following example shows that we can replace \verb!\doublerulesep! parameter with \verb!rulesep! key.
 \nopagebreak
 \begin{demohigh}
@@ -1335,6 +1402,8 @@
 \end{tblr}
 \end{demohigh}
 
+\subsection{Minimal Strut for Cell Text}
+
 The following example shows that we can replace \verb!\arraystretch! parameter with \verb!stretch! key.
 
 \begin{demohigh}
@@ -1345,6 +1414,8 @@
 \end{tblr}
 \end{demohigh}
 
+\subsection{Rowseps and Colseps for All}
+
 The following example uses \verb!rowsep! and \verb!colsep! keys to set padding for all rows and columns.
 \nopagebreak
 \begin{demohigh}
@@ -1356,6 +1427,8 @@
 \end{tblr}
 \end{demohigh}
 
+\subsection{Hspan and Vspan Algorithms}
+
 With \verb!hspan=default! or \verb!hspan=even!,
 \verb!tabularray! package will compute column widths from span widths.
 But with \verb!hspan=minimal!, it will compute span widths from column widths.
@@ -1419,57 +1492,103 @@
 \end{tblr}
 \end{demohigh}
 
-\section{Default Specifications}
+\subsection{Use Verbatim Commands}
 
-\verb!Tabularray! package provides \verb!\SetTblrInner! and \verb!\SetTblrOuter! commands
-for you to change the default inner and outer specifications of tables.
-Inner specifications are all specifications written in the mandatory argument of the \verb!tblr! environment,
-while outer specifications are all specifications written in the optional argument of the \verb!tblr! environment.
-At this time, most of the outer specifications are used for long tables (see Chapter \ref{chap:long}).
+With \verb!verb! key, you can write \verb!\verb! commands in the cell text:
 
-In the below example, the first line draws all hlines and vlines for all tables created afterwards,
-while the second line makes all tables created afterwards vertically align at bottom.
+\begin{demohigh}
+\begin{tblr}{hlines,verb}
+  20 & 30 & \verb!\hello{world}!40 \\
+  50 & \verb!\hello!60 & 70 \\
+\end{tblr}
+\end{demohigh}
 
-\begin{codehigh}
-\SetTblrInner{hlines,vlines}
-\SetTblrOuter{valign=b}
-\end{codehigh}
+\subsection{Set Baseline for the Table}
 
-You can define new \verb!tabularray! environments using \verb!\NewTblrEnviron! command:
+With \verb!baseline! key, you can set baseline for the table.
+All possible values for \verb!baseline! are as follows:
 
+\begin{center}
+\begin{tblr}{width=0.6\textwidth,colspec={cX[l]},hlines}
+  \V{t}    & align the table at the top \\
+  \V{T}    & align the table at the first row \\
+  \V{m}    & align the table at the middle, initial value \\
+  \V{b}    & align the table at the bottom \\
+  \V{B}    & align the table at the last row \\
+  \V{<n>}  & align the table at row \V{<n>} (a positive integer) \\
+\end{tblr}
+\end{center}
+
+If there is no hline above the first row, you get the same result with either \V{t} or \V{T}.
+But you get different results if there are one or more hlines above the row:
+
 \begin{demohigh}
-\NewTblrEnviron{mytblr}
-\SetTblrInner[mytblr]{hlines,vlines}
-\SetTblrOuter[mytblr]{valign=b}
-Text \begin{mytblr}{cccc}
- Alpha   & Beta  & Gamma  & Delta \\
- Epsilon & Zeta  & Eta    & Theta \\
- Iota    & Kappa & Lambda & Mu    \\
-\end{mytblr} Text
+Baseline\begin{tblr}{hlines,baseline=t}
+ Alpha   & Beta  & Gamma  \\
+ Epsilon & Zeta  & Eta    \\
+ Iota    & Kappa & Lambda \\
+\end{tblr}Baseline
 \end{demohigh}
 
-If not giving the optional argument to \verb!\SetTblrInner! or \verb!\SetTblrOuter! command,
-we set the default specifications for \verb!tblr! environment.
-And different tabularray environments could have different default specifications.
+\begin{demohigh}
+Baseline\begin{tblr}{hlines,baseline=T}
+ Alpha   & Beta  & Gamma  \\
+ Epsilon & Zeta  & Eta    \\
+ Iota    & Kappa & Lambda \\
+\end{tblr}Baseline
+\end{demohigh}
 
-\section{New Table Commands}
+The differences between \verb!b! and \verb!B! are similar to \verb!t! and \verb!T!.
+In fact, these two values \verb!T! and \verb!B! are better replacements
+for currently obsolete \verb!\firsthline! and \verb!\lasthline! commands.
 
-All commands which change the specifications of tables \textcolor{red3}{must} be defined with \verb!\NewTableCommand!.
-The following example demonstrates how to define a new table command:
+\section{Outer Specifications}
 
+Except for specifications to be introduced in Chapter \ref{chap:long},
+there are several other outer specifications which are described in Table~\ref{key:outer}.
+
+\begin{spectblr}[
+  caption = {Keys for Outer Specifications},
+  label = {key:outer},
+]{}
+  Key & Description and Values & Initial Value \\
+  \K{baseline} & set the baseline of the table & \V{m} \\
+  \K{long} & change the table to a long table & \None \\
+  \K{tall} & change the table to a tall table & \None \\
+  \K{expand} & you need this key to use verb commands & \None \\
+\end{spectblr}
+
+\subsection{Set Baseline in Another Way}
+
+You may notice that you can write \K{baseline} option as either an inner or an outer specification.
+It is true that either way would do the job. But there is a small difference:
+when \verb!baseline=t/T/m/b/B! is an outer specification,
+you can omit the key name and write the value only.
+
 \begin{demohigh}
-\NewTableCommand\myhline{\hline[0.1em,red5]}
-\begin{tblr}{llll}
-\myhline
- Alpha   & Beta  & Gamma   & Delta \\
- Epsilon & Zeta  & Eta     & Theta \\
- Iota    & Kappa & Lambda  & Mu    \\
-\myhline
-\end{tblr}
+Baseline\begin{tblr}[m]{hlines}
+ Alpha   & Beta  & Gamma  \\
+ Epsilon & Zeta  & Eta    \\
+ Iota    & Kappa & Lambda \\
+\end{tblr}Baseline
 \end{demohigh}
 
-\section{Expand Macros First}
+\subsection{Long and Tall Tables}
 
+You can change a table to long table by passing outer specification \K{long},
+or change it to tall table by passing outer specification \K{tall} (see Chapter~\ref{chap:long}).
+Therefore the following two tables are the same:
+\begin{codehigh}
+\begin{longtblr}{lcr}
+  Alpha & Beta & Gamma
+\end{longtblr}
+\begin{tblr}[long]{lcr}
+  Alpha & Beta & Gamma
+\end{tblr}
+\end{codehigh}
+
+\subsection{Expand Macros First}
+
 \verb!Tabularray! need to see every \verb!&! and \verb!\\! when splitting the table body
 with \verb!l3regex!. And you can not put cell text inside any table command defined with
 \verb!\NewTableCommand!. But you could use outer specification \verb!expand! to make \verb!tabularray!
@@ -1495,17 +1614,61 @@
 \end{tblr}
 \end{demohigh}
 
-With this \verb!expand! option, you can also use \verb!environ! package
-to define a new environment based on \verb!tblr! environment:
+\section{Default Specifications}
 
+\verb!Tabularray! package provides \verb!\SetTblrInner! and \verb!\SetTblrOuter! commands
+for you to change the default inner and outer specifications of tables.
+
+In the below example, the first line draws all hlines and vlines for all tables created afterwards,
+while the second line makes all tables created afterwards vertically align at the last row.
+
+\begin{codehigh}
+\SetTblrInner{hlines,vlines}
+\SetTblrOuter{baseline=B}
+\end{codehigh}
+
+\section{New Tabularray Environments}
+
+You can define new \verb!tabularray! environments using \verb!\NewTblrEnviron! command:
+
 \begin{demohigh}
-\NewEnviron{fancytblr}{
- Before Text
- \begin{tblr}[expand=\BODY]{hlines}
-   \BODY
- \end{tblr}
- After Text
-}
+\NewTblrEnviron{mytblr}
+\SetTblrInner[mytblr]{hlines,vlines}
+\SetTblrOuter[mytblr]{baseline=B}
+Text \begin{mytblr}{cccc}
+ Alpha   & Beta  & Gamma  & Delta \\
+ Epsilon & Zeta  & Eta    & Theta \\
+ Iota    & Kappa & Lambda & Mu    \\
+\end{mytblr} Text
+\end{demohigh}
+
+If not giving the optional argument to \verb!\SetTblrInner! or \verb!\SetTblrOuter! command,
+we set the default specifications for \verb!tblr! environment.
+And different tabularray environments could have different default specifications.
+
+\section{New General Environments}
+
+With \verb!+b! argument type of \verb!\NewDocumentEnvironment! command,
+you can also define a new general environment based on \verb!tblr! environment
+(note that there is an extra pair of curly braces at the end):
+
+\NewDocumentEnvironment{fancytblr}{+b}{
+  Before Text
+  \begin{tblr}{hlines}
+    #1
+  \end{tblr}
+  After Text
+}{}
+\begin{codehigh}
+\NewDocumentEnvironment{fancytblr}{+b}{
+  Before Text
+  \begin{tblr}{hlines}
+    #1
+  \end{tblr}
+  After Text
+}{}
+\end{codehigh}
+\begin{demohigh}
 \begin{fancytblr}
   One   & Two   & Three \\
   Four  & Five  & Six   \\
@@ -1513,17 +1676,63 @@
 \end{fancytblr}
 \end{demohigh}
 
-\section{Use Verbatim Commands}
+\section{New Table Commands}
 
-With inner specification \verb!verb!, you can write \verb!\verb! commands in the cell text:
+All commands which change the specifications of tables \textcolor{red3}{must} be defined with \verb!\NewTableCommand!.
+The following example demonstrates how to define a new table command:
 
 \begin{demohigh}
-\begin{tblr}{hlines,verb}
-  20 & 30 & \verb!\hello{world}!40 \\
-  50 & \verb!\hello!60 & 70 \\
+\NewTableCommand\myhline{\hline[0.1em,red5]}
+\begin{tblr}{llll}
+\myhline
+ Alpha   & Beta  & Gamma   & Delta \\
+ Epsilon & Zeta  & Eta     & Theta \\
+ Iota    & Kappa & Lambda  & Mu    \\
+\myhline
 \end{tblr}
 \end{demohigh}
 
+\section{Odd and Even Selectors}
+
+From version 2022A, child selectors \verb!odd! and \verb!even! accept an optional argument,
+in which you can specify the start index and the end index of the children.
+
+\begin{demohigh}
+\begin{tblr}{
+  cell{odd}{1} = {red9},
+  cell{odd[4]}{2} = {green9},
+  cell{odd[3-X]}{3} = {blue9},
+}
+  Head   & Head    & Head   \\
+  Talk A & Place A & Date A \\
+  Talk B & Place B & Date B \\
+  Talk C & Place C & Date C \\
+  Talk D & Place D & Date D \\
+  Talk E & Place E & Date E \\
+  Talk F & Place F & Date F \\
+  Talk G & Place G & Date G \\
+  Talk H & Place H & Date H \\
+\end{tblr}
+\end{demohigh}
+
+\begin{demohigh}
+\begin{tblr}{
+  cell{even}{1} = {yellow9},
+  cell{even[4]}{2} = {cyan9},
+  cell{even[3-X]}{3} = {purple9},
+}
+  Head   & Head    & Head   \\
+  Talk A & Place A & Date A \\
+  Talk B & Place B & Date B \\
+  Talk C & Place C & Date C \\
+  Talk D & Place D & Date D \\
+  Talk E & Place E & Date E \\
+  Talk F & Place F & Date F \\
+  Talk G & Place G & Date G \\
+  Talk H & Place H & Date H \\
+\end{tblr}
+\end{demohigh}
+
 \section{Counters and Lengths}
 
 Counters \verb!rownum!, \verb!colnum!, \verb!rowcount!, \verb!colcount! can be used in cell text:
@@ -1773,7 +1982,7 @@
 
 As you can see in the above example, the appearance of long tables of \verb!tabularray! package
 is similar to that of \verb!threeparttablex! packages.
-We support table footnotes, but not page footnotes in \verb!tabularray! package.
+It supports table footnotes, but not page footnotes.
 
 \newpage
 
@@ -1837,7 +2046,7 @@
 \end{longtblr}
 \end{codehigh}
 
-As you can see in the above code, we typeset long tables with \verb!longtblr! environemnt.
+As you can see in the above code, we typeset long tables with \verb!longtblr! environment.
 And we can totally separate contents and styles of long tables with \verb!tabularray! package.
 
 Row head and row foot consist of some lines of the table and should appear in every page.
@@ -1885,7 +2094,9 @@
 
 The template system for table heads and table foots in \verb!tabularray! is largely inspired
 by \verb!beamer!, \verb!caption! and \verb!longtable! packages. For elements in Table \ref{tblr:element},
-you can use \verb!\DefTblrTemplate! to define and modify templates,
+you can use \verb!\DefTblrTemplate!\footnote{From version 2022A,
+\texttt{\string\DefTblrTemplate} has another name \texttt{\string\DeclareTblrTemplate}.}
+to define and modify templates,
 and use \verb!\SetTblrTemplate! to choose default templates. In defining templates,
 you can include other templates with \verb!\UseTblrTemplate! and \verb!\ExpTblrTemplate! commands.
 
@@ -1996,7 +2207,7 @@
   \UseTblrTemplate{caption-tag}{default}
   \UseTblrTemplate{caption-sep}{default}
   \UseTblrTemplate{caption-text}{default}
-  \UseTblrTemplate{conthead}{default}
+  \UseTblrTemplate{conthead-text}{default}
 }
 \end{codehigh}
 
@@ -2066,7 +2277,15 @@
 \end{codehigh}
 
 Note that you can define the same template for multiple elements in \verb!\DefTblrTemplate! command.
+If you only want to show table caption in the first page, you may change the definitions of
+\verb!middlehead! and \verb!lasthead! elements:
 
+\begin{codehigh}
+\DefTblrTemplate{middlehead,lasthead}{default}{
+  \UseTblrTemplate{conthead}{default}
+}
+\end{codehigh}
+
 \section{Change Styles}
 
 All available keys for template elements are described in Table \ref{key:element}.
@@ -2077,12 +2296,14 @@
   remark{Note} = {In most cases, you can omit the underlined key names and write only their values.
                   The keys \K{halign}, \K{indent} and \K{hang} are only for main templates.}
 ]{}
-  Key Name               & Key Description \\
-  \underline{\K{fg}}     & foreground color \\
-  \underline{\K{font}}   & font commands \\
-  \underline{\K{halign}} & horizontal alignment: \V{l} (left), \V{c} (center), or \V{r} (right) \\
-  \K{indent}             & parindent value \\
-  \K{hang}               & hangindent value \\
+  Key Name               & Key Description  & Initial Value\\
+  \underline{\K{fg}}     & foreground color & \None \\
+  \underline{\K{font}}   & font commands    & \None \\
+  \underline{\K{halign}}
+     & horizontal alignment: \V{l} (left), \V{c} (center), \V{r} (right) or \V{j} (justify)
+                                            & \V{j} \\
+  \K{indent}             & parindent value  & \V{0pt} \\
+  \K{hang}               & hangindent value & \V{0pt} or \V{0.7em} \\
 \end{spectblr}
 
 You may change the styles of elements with \verb!\SetTblrStyle! command:
@@ -2228,7 +2449,7 @@
 \end{tblr}
 \end{demohigh}
 
-If you need more than one cmidrules, you can use \verb!\cmidrulemore! command.
+If you need more than one \verb!\cmidrule!s, you can use \verb!\cmidrulemore! command.
 
 \begin{demohigh}
 \begin{tblr}{llll}
@@ -2320,6 +2541,9 @@
 \end{booktabs}
 \end{demohigh}
 
+From version 2022A, there is a \verb!longtabs! environment for writing long \verb!booktabs! tables,
+and a \verb!talltabs! environment for writing tall \verb!booktabs! tables.
+
 \section{Library \texttt{counter}}
 
 You need to load \verb!counter! library with \verb!\UseTblrLibrary{counter}!,
@@ -2434,13 +2658,12 @@
 This causes an error if a cell contains some vertical material, such as lists or display maths.
 
 With \verb!\UseTblrLibrary{varwidth}! in the preamble of the document,
-\verb!tabularray! loads \verb!varwidth! package,
-and adds a new inner specification \verb!measure! for tables.
+\verb!tabularray! will load \verb!varwidth! package,
+and add a new inner specification \verb!measure! for tables.
 After setting \verb!measure=vbox!, it will use \verb!\vbox! to measure cell widths.
 
 \begin{demohigh}
-\begin{tblr}{measure=vbox}
-\hline
+\begin{tblr}{hlines,measure=vbox}
   Text Text Text Text Text Text Text
   \begin{itemize}
     \item List List List List List List
@@ -2447,10 +2670,81 @@
     \item List List List List List List List
   \end{itemize}
   Text Text Text Text Text Text Text \\
-\hline
 \end{tblr}
 \end{demohigh}
 
+From version 2022A, you can remove extra space above and below lists,
+by adding option \verb!stretch=-1!.
+The following example also needs \verb!enumitem! package and its \verb!nosep! option:
+
+{\centering\begin{tblr}{
+  hlines,vlines,rowspec={Q[l,t]Q[l,b]},
+  measure=vbox,stretch=-1,
+}
+  \begin{itemize}[nosep]
+    \item List List List List List
+    \item List List List List List List
+  \end{itemize} & oooo \\
+  \begin{itemize}[nosep]
+    \item List List List List List
+    \item List List List List List List
+  \end{itemize} & gggg \\
+\end{tblr}\par}
+
+%% BUG: there is extra vertical space at the beginning of the first cell if I use demohigh
+%\begin{demohigh}
+\begin{codehigh}
+\begin{tblr}{
+  hlines,vlines,rowspec={Q[l,t]Q[l,b]},
+  measure=vbox,stretch=-1,
+}
+  \begin{itemize}[nosep]
+    \item List List List List List
+    \item List List List List List List
+  \end{itemize} & oooo \\
+  \begin{itemize}[nosep]
+    \item List List List List List
+    \item List List List List List List
+  \end{itemize} & gggg \\
+\end{tblr}
+\end{codehigh}
+%\end{demohigh}
+
+Note that option \verb!stretch=-1! also removes struts from cells, therefore it may not work well
+in \verb!tabularray! environments with \verb!rowsep=0pt!, such as
+\verb!booktabs!/\verb!longtabs!/\verb!talltabs! environments from \verb!booktabs! library.
+
+\chapter{History and Future}
+
+\section{The Future}
+
+Starting from 2022, except for hotfix releases for critical bugs,
+all new releases will be published only in March, June, September or December.
+You may watch the milestones page for the scheduled dates of upcoming releases
+and their changes:\newline
+\centerline{\url{https://github.com/lvjr/tabularray/milestones}}
+
+To make the upcoming releases more stable, you are very welcome to test the latest package file
+in the repository. To test it, you only need to download the following \verb!tabularray.sty!
+and put it into the folder of your TeX documents:\newline
+\centerline{\url{https://github.com/lvjr/tabularray/raw/main/tabularray.sty}}
+
+\section{The History}
+
+The change log of \verb!tabularray! package will be updated on the wiki page:\newline
+\centerline{\url{https://github.com/lvjr/tabularray/wiki/ChangeLog}}
+
+In version 2022A, there were several breaking changes:
+
+\begin{itemize}[nosep]
+  \item \verb!\multicolumn! command was removed; it is better to use \verb!\SetCell! command.
+  \item \verb!\multirow! command was removed; it is better to use \verb!\SetCell! command.
+  \item \verb!\firsthline! command was removed; it is better to use \verb!baseline=T! option.
+  \item \verb!\lasthline! command was removed; it is better to use \verb!baseline=B! option.
+\end{itemize}
+
+For your old documents, you can still rollback to version 2021 by \verb!\usepackage{tabularray}[=v2021]!.
+
 \chapter{The Source Code}
 
 %\CodeHigh{lite}

Modified: trunk/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty	2022-03-01 21:52:45 UTC (rev 62327)
+++ trunk/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty	2022-03-01 21:53:05 UTC (rev 62328)
@@ -12,14 +12,13 @@
 
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
-\ProvidesExplPackage{tabularray}{2021-06-05}{2021K}
+\ProvidesExplPackage{tabularray}{2021-12-01}{2021Q}
   {Typeset tabulars and arrays with LaTeX3}
 
 \RequirePackage{xparse}
+
 \AtBeginDocument{\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}}
 
-\ExplSyntaxOn
-
 %% Backport \tl_if_eq:NnTF for old texlive 2020
 \cs_if_exist:NF \tl_if_eq:NnTF
   {
@@ -53,10 +52,12 @@
 \cs_generate_variant:Nn \tl_const:Nn { ce }
 \cs_generate_variant:Nn \tl_log:n { x }
 \cs_generate_variant:Nn \tl_gput_right:Nn { Nf }
+\cs_generate_variant:Nn \tl_put_left:Nn { Nv }
 \prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF }
 \prg_generate_conditional_variant:Nnn \prop_if_in:Nn { c } { T }
 \prg_generate_conditional_variant:Nnn \str_if_eq:nn { xn } { TF }
 \prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T, TF }
+\prg_generate_conditional_variant:Nnn \tl_if_head_eq_catcode:nN { VN } { TF }
 \prg_generate_conditional_variant:Nnn \tl_if_head_eq_meaning:nN { VN } { T, TF }
 
 \tl_new:N  \l__tblr_a_tl
@@ -97,12 +98,34 @@
 \box_new:N \l__tblr_c_box % for cell box
 \box_new:N \l__tblr_d_box
 
-%% Some counters for row and column numbering
-\newcounter{rownum}
-\newcounter{colnum}
-\newcounter{rowcount}
-\newcounter{colcount}
+%% Total number of tblr tables
+\int_new:N \g__tblr_table_count_int
 
+%% Some commands for horizontal alignment
+\cs_new_eq:NN \__tblr_halign_command_l: \raggedright
+\cs_new_eq:NN \__tblr_halign_command_c: \centering
+\cs_new_eq:NN \__tblr_halign_command_r: \raggedleft
+
+%% Some counters for row and column numbering.
+%% We may need to restore all LaTeX counters in measuring and building cells,
+%% so we must not define these counters with \newcounter command.
+\int_new:N \c at rownum
+\int_new:N \c at colnum
+\int_new:N \c at rowcount
+\int_new:N \c at colcount
+
+%% Add missing \therownum, \thecolnum, \therowcount, \thecolcount (issue #129)
+\NewExpandableDocumentCommand \therownum {} { \@arabic \c at rownum }
+\NewExpandableDocumentCommand \thecolnum {} { \@arabic \c at colnum }
+\NewExpandableDocumentCommand \therowcount {} { \@arabic \c at rowcount }
+\NewExpandableDocumentCommand \thecolcount {} { \@arabic \c at colcount }
+
+%% Some dimensions for row and column spacing
+\dim_new:N \abovesep
+\dim_new:N \belowsep
+\dim_new:N \leftsep
+\dim_new:N \rightsep
+
 %%% --------------------------------------------------------
 %%  \section{Data Structures Based on Property Lists}
 %%% --------------------------------------------------------
@@ -113,7 +136,10 @@
   {
     \prop_gclear_new:c { g__tblr_text_ \int_use:N \g_tblr_level_int _prop }
     \prop_gclear_new:c { g__tblr_command_ \int_use:N \g_tblr_level_int _prop }
-    \prop_gclear_new:c { g__tblr_table_ \int_use:N \g_tblr_level_int _prop }
+    \prop_gclear_new:c { g__tblr_inner_ \int_use:N \g_tblr_level_int _prop }
+    \prop_gclear_new:c { g__tblr_note_ \int_use:N \g_tblr_level_int _prop }
+    \prop_gclear_new:c { g__tblr_remark_ \int_use:N \g_tblr_level_int _prop }
+    \prop_gclear_new:c { g__tblr_more_ \int_use:N \g_tblr_level_int _prop }
     \prop_gclear_new:c { g__tblr_row_ \int_use:N \g_tblr_level_int _prop }
     \prop_gclear_new:c { g__tblr_column_ \int_use:N \g_tblr_level_int _prop }
     \prop_gclear_new:c { g__tblr_cell_ \int_use:N \g_tblr_level_int _prop }
@@ -184,7 +210,7 @@
       { \dim_compare_p:nNn { #3 } > { \l__tblr_put_if_larger_tl } }
       { \prop_put:Nnn #1 { #2 } { #3 }  }
   }
-\cs_generate_variant:Nn \__tblr_put_if_larger:Nnn { Nnx, Nxn, Nxx }
+\cs_generate_variant:Nn \__tblr_put_if_larger:Nnn { Nnx, Nxn, Nxx, NnV }
 
 \cs_new_protected:Npn \__tblr_gput_if_larger:Nnn #1 #2 #3
   {
@@ -215,63 +241,78 @@
 %%  \section{Data Structures Based on Token Lists}
 %%% --------------------------------------------------------
 
-\cs_new_protected:Npn \__tblr_clear_text_lists:
+\cs_new_protected:Npn \__tblr_clear_spec_lists:
   {
-    \__tblr_clear_one_text_lists:n { text }
-    \__tblr_clear_one_text_lists:n { hline }
-    \__tblr_clear_one_text_lists:n { vline }
+    %\__tblr_clear_one_spec_lists:n { row }
+    %\__tblr_clear_one_spec_lists:n { column }
+    %\__tblr_clear_one_spec_lists:n { cell }
+    \__tblr_clear_one_spec_lists:n { text }
+    \__tblr_clear_one_spec_lists:n { hline }
+    \__tblr_clear_one_spec_lists:n { vline }
+    \__tblr_clear_one_spec_lists:n { outer }
   }
 
-\cs_new_protected:Npn \__tblr_clear_one_text_lists:n #1
+\cs_new_protected:Npn \__tblr_clear_one_spec_lists:n #1
   {
     \clist_if_exist:cTF { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
       {
         \clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
           {
-            \tl_gclear:c { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_##1_tl }
+            \tl_gclear:c { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_##1_tl }
           }
       }
       { \clist_new:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } }
   }
 
-\cs_new_protected:Npn \__tblr_text_gput:nnn #1 #2 #3
+\cs_new_protected:Npn \__tblr_spec_gput:nnn #1 #2 #3
   {
     \tl_gset:cn
-      { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl } {#3}
+      { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl } {#3}
     \clist_gput_right:cx { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } {#2}
   }
-\cs_generate_variant:Nn \__tblr_text_gput:nnn { nne, nnV, nen, nee, neV }
+\cs_generate_variant:Nn \__tblr_spec_gput:nnn { nne, nnV, nen, nee, neV }
 
-\cs_new:Npn \__tblr_text_item:nn #1 #2
+\cs_new:Npn \__tblr_spec_item:nn #1 #2
   {
-    \tl_if_exist:cT { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl }
+    \tl_if_exist:cT { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl }
       {
         \exp_args:Nv \exp_not:n
-          { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl }
+          { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl }
       }
   }
-\cs_generate_variant:Nn \__tblr_text_item:nn { ne }
+\cs_generate_variant:Nn \__tblr_spec_item:nn { ne }
 
-\cs_new_protected:Npn \__tblr_text_gput_if_larger:nnn #1 #2 #3
+\cs_new_protected:Npn \__tblr_spec_gput_if_larger:nnn #1 #2 #3
   {
-    \tl_set:Nx \l__tblr_put_if_larger_tl { \__tblr_text_item:nn {#1} {#2} }
+    \tl_set:Nx \l__tblr_put_if_larger_tl { \__tblr_spec_item:nn {#1} {#2} }
     \bool_lazy_or:nnT
       { \tl_if_empty_p:N \l__tblr_put_if_larger_tl }
       { \dim_compare_p:nNn {#3} > { \l__tblr_put_if_larger_tl } }
-      { \__tblr_text_gput:nnn {#1} {#2} {#3} }
+      { \__tblr_spec_gput:nnn {#1} {#2} {#3} }
   }
-\cs_generate_variant:Nn \__tblr_text_gput_if_larger:nnn { nne, nnV, nen, nee, neV }
+\cs_generate_variant:Nn \__tblr_spec_gput_if_larger:nnn { nne, nnV, nen, nee, neV }
 
-\cs_new_protected:Npn \__tblr_text_log:n #1
+\cs_new_protected:Npn \__tblr_spec_gadd_dimen_value:nnn #1 #2 #3
   {
+    \__tblr_spec_gput:nne {#1} {#2}
+      { \dim_eval:n { \__tblr_spec_item:ne {#1} {#2} + #3 } }
+  }
+\cs_generate_variant:Nn \__tblr_spec_gadd_dimen_value:nnn { nne, nnV, nen, nee }
+
+\cs_new_protected:Npn \__tblr_spec_log:n #1
+  {
     \clist_gremove_duplicates:c
       { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
-    \tl_log:n { ----------~----------~----------~----------~---------- }
+    \tl_log:x
+      {
+        The ~ spec ~ list ~ #1 _ \int_use:N \g_tblr_level_int
+              \space contains ~ the ~ pairs:
+      }
     \clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
       {
         \tl_log:x
           {
-            \space { #1 ##1 } ~\space=>~\space { \__tblr_text_item:nn {#1} {##1} }
+            \space { ##1 } ~\space=>~\space { \__tblr_spec_item:nn {#1} {##1} }
           }
       }
   }
@@ -321,6 +362,7 @@
 \__tblr_data_new_key:nnn { row } { @row-foot }   { dim }
 \__tblr_data_new_key:nnn { row } { @row-upper }  { dim }
 \__tblr_data_new_key:nnn { row } { @row-lower }  { dim }
+\__tblr_data_new_key:nnn { row } { break }       { int }
 
 \int_new:N \g__tblr_data_column_key_count_int
 \__tblr_data_new_key:nnn { column } { width }       { dim }
@@ -336,6 +378,10 @@
 \__tblr_data_new_key:nnn { cell } { halign }       { str }
 \__tblr_data_new_key:nnn { cell } { valign }       { str }
 \__tblr_data_new_key:nnn { cell } { background }   { str }
+\__tblr_data_new_key:nnn { cell } { foreground }   { str }
+\__tblr_data_new_key:nnn { cell } { font }         { str }
+\__tblr_data_new_key:nnn { cell } { mode }         { str }
+\__tblr_data_new_key:nnn { cell } { cmd }          { str }
 \__tblr_data_new_key:nnn { cell } { omit }         { int }
 \__tblr_data_new_key:nnn { cell } { @cell-width }  { dim }
 \__tblr_data_new_key:nnn { cell } { @cell-height } { dim }
@@ -350,12 +396,12 @@
 \tl_const:Nn \g__tblr_data_cell_index_number_tl {2}
 \int_new:N \g__tblr_array_int
 
-\cs_new_protected:Npn \__tblr_initial_table_data:
+\cs_new_protected:Npn \__tblr_init_table_data:
   {
-    \clist_map_function:NN \g__tblr_data_clist \__tblr_initial_one_data:n
+    \clist_map_function:NN \g__tblr_data_clist \__tblr_init_one_data:n
   }
 
-\cs_new_protected:Npn \__tblr_initial_one_data:n #1
+\cs_new_protected:Npn \__tblr_init_one_data:n #1
   {
     \int_gincr:N \g__tblr_array_int
     \intarray_new:cn { g__tblr_#1_ \int_use:N \g__tblr_array_int _intarray }
@@ -507,18 +553,18 @@
 
 \cs_new_protected:Npn \__tblr_data_int_from_str:n #1
   {
-    \tl_if_exist:cTF { g__tblr_data_#1_to_int_tl }
+    \tl_if_exist:cTF { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
       {
         \tl_gset_eq:Nc \g__tblr_data_int_from_value_tl
-          { g__tblr_data_#1_to_int_tl }
+          { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
       }
       {
         \int_gincr:N \g__tblr_data_str_value_count_int
-        \tl_gset:cx { g__tblr_data_#1_to_int_tl }
+        \tl_gset:cx { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
           { \int_use:N \g__tblr_data_str_value_count_int }
-        \tl_gset:cx
+        \tl_gset:cn
           { g__tblr_data_ \int_use:N \g__tblr_data_str_value_count_int _to_str_tl }
-          { #1 }
+          { \exp_not:n {#1} }
         \tl_gset:Nx \g__tblr_data_int_from_value_tl
           { \int_use:N \g__tblr_data_str_value_count_int }
       }
@@ -661,7 +707,8 @@
       { \__tblr_data_key_to_int:nnn {#1} {#2} {#3} }
       { \g__tblr_data_int_from_value_tl }
   }
-\cs_generate_variant:Nn \__tblr_data_gadd_dimen_value:nnnn { nnne, nnnV, nene }
+\cs_generate_variant:Nn \__tblr_data_gadd_dimen_value:nnnn
+  { nnne, nnnV, nenn, nene }
 
 \cs_new_protected:Npn \__tblr_array_gadd_value:Nnn #1 #2 #3
   {
@@ -678,39 +725,39 @@
       {
         \cs_set_protected:Npn \__tblr_data_gput:nnnn #1 #2 #3 #4
           {
-            \__tblr_prop_gput:nnn {#1} { [#2] / #3 } {#4}
+            \__tblr_spec_gput:nnn {#1} { [#2] / #3 } {#4}
           }
         \cs_set_protected:Npn \__tblr_data_gput:nnnnn #1 #2 #3 #4 #5
           {
-            \__tblr_prop_gput:nnn {#1} { [#2][#3] / #4 } {#5}
+            \__tblr_spec_gput:nnn {#1} { [#2][#3] / #4 } {#5}
           }
         \cs_set:Npn \__tblr_data_item:nnn #1 #2 #3
           {
-            \__tblr_prop_item:nn {#1} { [#2] / #3 }
+            \__tblr_spec_item:nn {#1} { [#2] / #3 }
           }
         \cs_set:Npn \__tblr_data_item:nnnn #1 #2 #3 #4
           {
-            \__tblr_prop_item:nn {#1} { [#2][#3] / #4 }
+            \__tblr_spec_item:nn {#1} { [#2][#3] / #4 }
           }
         \cs_set_protected:Npn \__tblr_data_log:n #1
           {
-            \__tblr_prop_log:n {#1}
+            \__tblr_spec_log:n {#1}
           }
         \cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnn #1 #2 #3 #4
           {
-            \__tblr_prop_gput_if_larger:nnn {#1} { [#2] / #3 } {#4}
+            \__tblr_spec_gput_if_larger:nnn {#1} { [#2] / #3 } {#4}
           }
         \cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnnn #1 #2 #3 #4 #5
           {
-            \__tblr_prop_gput_if_larger:nnn {#1} { [#2][#3] / #4 } {#5}
+            \__tblr_spec_gput_if_larger:nnn {#1} { [#2][#3] / #4 } {#5}
           }
         \cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnn #1 #2 #3 #4
           {
-            \__tblr_prop_gadd_dimen_value:nnn {#1} { [#2] / #3 } {#4}
+            \__tblr_spec_gadd_dimen_value:nnn {#1} { [#2] / #3 } {#4}
           }
         \cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnnn #1 #2 #3 #4 #5
           {
-            \__tblr_prop_gadd_dimen_value:nnn {#1} { [#2][#3] / #4 } {#5}
+            \__tblr_spec_gadd_dimen_value:nnn {#1} { [#2][#3] / #4 } {#5}
           }
       }
   }
@@ -818,12 +865,30 @@
       }
   }
 
+\tl_new:N \l__tblr_child_from_tl
+\tl_new:N \l__tblr_child_to_tl
+
 \cs_new_protected_nopar:Npn \__tblr_get_childs_normal_aux:w #1 - #2 \scan_stop
   {
-    \int_step_inline:nnn {#1} {#2}
+    \__tblr_child_name_to_index:nN {#1} \l__tblr_child_from_tl
+    \__tblr_child_name_to_index:nN {#2} \l__tblr_child_to_tl
+    \int_step_inline:nnn { \l__tblr_child_from_tl } { \l__tblr_child_to_tl }
       { \clist_put_right:Nn \l_tblr_childs_clist {##1} }
   }
 
+\regex_const:Nn \c__tblr_child_name_regex { ^ [X-Z] $ }
+
+%% Convert X, Y, Z to the indexes of the last three childs, respectively
+\cs_new_protected_nopar:Npn \__tblr_child_name_to_index:nN #1 #2
+  {
+    \regex_match:NnTF \c__tblr_child_name_regex {#1}
+      {
+        \tl_set:Nx #2
+          { \int_eval:n { \l_tblr_childs_total_tl + \int_from_alph:n {#1} - 26 } }
+      }
+      { \tl_set:Nx #2 { #1 } }
+  }
+
 %%% --------------------------------------------------------
 %%  \section{New Table Commands}
 %%% --------------------------------------------------------
@@ -889,7 +954,55 @@
     \int_set:Nn \c at colnum {#2}
   }
 
+%% Table commands are defined only inside tblr environments,
+%% but some packages such as csvsimple need to use them outside tblr environments,
+%% therefore we define some of them first here.
+\ProvideDocumentCommand \SetHlines  { o m m } {}
+\ProvideDocumentCommand \SetHline   { o m m } {}
+\ProvideDocumentCommand \SetVlines  { o m m } {}
+\ProvideDocumentCommand \SetVline   { o m m } {}
+\ProvideDocumentCommand \SetCells   { o m } {}
+\ProvideDocumentCommand \SetCell    { o m } {}
+\ProvideDocumentCommand \SetRows    { o m } {}
+\ProvideDocumentCommand \SetRow     { o m } {}
+\ProvideDocumentCommand \SetColumns { o m } {}
+\ProvideDocumentCommand \SetColumn  { o m } {}
+
 %%% --------------------------------------------------------
+%%> \section{New Content Commands}
+%%% --------------------------------------------------------
+
+%% We need to emulate or fix some commands such as \diagbox in other packages
+%% These commands must be defined with \NewContentCommand command
+%% We only enable them inside tblr environment to avoid potential conflict
+
+\clist_new:N \g__tblr_content_commands_clist
+
+\msg_new:nnn { tabularray } { defined-content-command }
+  { Content ~ commnad ~ #1 has ~ been ~ defined! }
+
+\NewDocumentCommand \NewContentCommand { m O{0} o m }
+  {
+    \clist_if_in:NnTF \g__tblr_content_commands_clist { #1 }
+      {
+        \msg_warning:nnn { tabularray } { defined-content-command } { #1 }
+        \clist_log:N \g__tblr_content_commands_clist
+      }
+      {
+        \__tblr_make_xparse_arg_spec:nnN { #2 } { #3 } \l__tblr_a_tl
+        \exp_args:NcV \NewDocumentCommand
+          { __tblr_content_command_ \cs_to_str:N #1 :w } \l__tblr_a_tl { #4 }
+        \clist_gput_right:Nn \g__tblr_content_commands_clist { #1 }
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_enable_content_commands:
+  {
+    \clist_map_inline:Nn \g__tblr_content_commands_clist
+      { \cs_set_eq:Nc ##1 { __tblr_content_command_ \cs_to_str:N ##1 :w } }
+  }
+
+%%% --------------------------------------------------------
 %%  \section{New Dash Styles}
 %%% --------------------------------------------------------
 
@@ -1007,11 +1120,18 @@
 \tl_new:N \l__tblr_hline_dash_tl  % dash style
 \tl_new:N \l__tblr_hline_fg_tl    % dash foreground
 \tl_new:N \l__tblr_hline_wd_tl    % dash width
+\tl_new:N \l__tblr_hline_leftpos_tl  % left position
+\tl_new:N \l__tblr_hline_rightpos_tl % right position
+\bool_new:N \l__tblr_hline_endpos_bool % whether set positions only for both ends
 
 \NewTableCommand \cline [2] [] { \SetHline [=] {#2} {#1} }
 
 \NewTableCommand \hline [1] [] { \SetHline [+] {-} {#1} }
 
+%% Some keys can be set by any hline, such as abovespace and belowspace keys.
+%% Using special hline of index 0, you can set these keys without adding any hlines.
+\NewTableCommand \SetVspace [1] { \SetHline [0] {-} {#1} }
+
 %% #1: the index of the hline (may be + or =)
 %% #2: which columns of the hline, separate by commas
 %% #3: key=value pairs
@@ -1025,13 +1145,19 @@
 \cs_new_protected:Npn \tblr_set_hline:nnn #1 #2 #3
   {
     \group_begin:
-    \keys_set_groups:nnn { tblr-hline } { text } {#3}
-    \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr at text }
+    %% We can not use \int_compare:nNnTF here since #1 may be + or = .
+    %% Also we treat hline of index 0 specially, not adding hline count.
+    \tl_if_eq:nnTF {#1} {0}
+      { \keys_set:nn { tblr-hline } {#3} }
       {
-        \__tblr_set_hline_num:n {#1}
-        \tl_clear:N \l__tblr_hline_dash_tl
-        \keys_set:nn { tblr-hline } { dash = solid, #3 }
-        \__tblr_set_hline_cmd:n {#2}
+        \keys_set_groups:nnn { tblr-hline } { text } {#3}
+        \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr at text }
+          {
+            \__tblr_set_hline_num:n {#1}
+            \tl_clear:N \l__tblr_hline_dash_tl
+            \keys_set:nn { tblr-hline } { dash = solid, #3 }
+            \__tblr_set_hline_cmd:n {#2}
+          }
       }
     \group_end:
   }
@@ -1068,12 +1194,12 @@
   {
     \tl_clear:N \l__tblr_hline_num_tl
     \tl_set:Nx \l__tblr_hline_count_tl
-      { \__tblr_text_item:ne { hline } { [\int_use:N \c at rownum] / @hline-count } }
+      { \__tblr_spec_item:ne { hline } { [\int_use:N \c at rownum] / @hline-count } }
     %% \l__tblr_hline_count_tl may be empty when rowspec has extra |'s
     \int_compare:nNnTF { \l__tblr_hline_count_tl + 0 } = {0}
       {
         \tl_set:Nx \l__tblr_hline_num_tl { 1 }
-        \__tblr_text_gput:nen { hline }
+        \__tblr_spec_gput:nen { hline }
           { [\int_use:N \c at rownum] / @hline-count } { 1 }
       }
       {
@@ -1095,7 +1221,7 @@
   {
     \tl_set:Nx \l__tblr_hline_count_tl
       { \int_eval:n { \l__tblr_hline_count_tl + 1 } }
-    \__tblr_text_gput:nee { hline }
+    \__tblr_spec_gput:nee { hline }
       { [\int_use:N \c at rownum] / @hline-count } { \l__tblr_hline_count_tl }
     \tl_set_eq:NN \l__tblr_hline_num_tl \l__tblr_hline_count_tl
   }
@@ -1108,6 +1234,21 @@
     wd .code:n = \tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {#1} },
     fg .code:n = \tl_set:Nn \l__tblr_hline_fg_tl {#1},
     baseline .code:n = \__tblr_hline_set_baseline:n {#1},
+    leftpos  .code:n = \tl_set:Nx \l__tblr_hline_leftpos_tl {#1},
+    rightpos .code:n = \tl_set:Nx \l__tblr_hline_rightpos_tl {#1},
+    l        .meta:n = { leftpos = #1 },
+    l     .default:n = { -0.8 },
+    r        .meta:n = { rightpos = #1 },
+    r     .default:n = { -0.8 },
+    lr       .meta:n = { leftpos = #1, rightpos = #1 },
+    lr    .default:n = { -0.8 },
+    endpos .bool_set:N = \l__tblr_hline_endpos_bool,
+    abovespace .code:n = \__tblr_row_gput_above:ne { belowsep } { \dim_eval:n {#1} },
+    belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
+    abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne
+                          { belowsep } { \dim_eval:n {#1} },
+    belowspace+ .code:n = \__tblr_row_gadd_dimen:ne
+                          { abovesep } { \dim_eval:n {#1} },
     unknown .code:n = \__tblr_hline_unknown_key:V \l_keys_key_str,
   }
 
@@ -1131,24 +1272,59 @@
     \__tblr_get_childs:nx {#1} { \int_use:N \c at colcount }
     \clist_map_inline:Nn \l_tblr_childs_clist
       {
-        \__tblr_text_gput:nee { hline }
-          { [\int_use:N \c at rownum][##1](\l__tblr_hline_num_tl) / @dash }
-          { \l__tblr_hline_dash_tl }
+        \__tblr_set_hline_option:nnn { ##1 } { @dash } { \l__tblr_hline_dash_tl }
         \tl_if_empty:NF \l__tblr_hline_wd_tl
           {
-            \__tblr_text_gput:nee { hline }
-              { [\int_use:N \c at rownum][##1](\l__tblr_hline_num_tl) / wd }
-              { \l__tblr_hline_wd_tl }
+            \__tblr_set_hline_option:nnn { ##1 } { wd } { \l__tblr_hline_wd_tl }
           }
         \tl_if_empty:NF \l__tblr_hline_fg_tl
           {
-            \__tblr_text_gput:nee { hline }
-              { [\int_use:N \c at rownum][##1](\l__tblr_hline_num_tl) / fg }
-              { \l__tblr_hline_fg_tl }
+            \__tblr_set_hline_option:nnn { ##1 } { fg } { \l__tblr_hline_fg_tl }
           }
       }
+    \tl_if_empty:NF \l__tblr_hline_leftpos_tl
+      {
+        \bool_if:NTF \l__tblr_hline_endpos_bool
+          {
+            \__tblr_set_hline_option:nnn
+              { \clist_item:Nn \l_tblr_childs_clist {1} }
+              { leftpos }
+              { \l__tblr_hline_leftpos_tl }
+          }
+          {
+            \clist_map_inline:Nn \l_tblr_childs_clist
+              {
+                \__tblr_set_hline_option:nnn
+                  { ##1 } { leftpos } { \l__tblr_hline_leftpos_tl }
+              }
+          }
+      }
+    \tl_if_empty:NF \l__tblr_hline_rightpos_tl
+      {
+        \bool_if:NTF \l__tblr_hline_endpos_bool
+          {
+            \__tblr_set_hline_option:nnn
+              { \clist_item:Nn \l_tblr_childs_clist {-1} }
+              { rightpos }
+              { \l__tblr_hline_rightpos_tl }
+          }
+          {
+            \clist_map_inline:Nn \l_tblr_childs_clist
+              {
+                \__tblr_set_hline_option:nnn
+                  { ##1 } { rightpos } { \l__tblr_hline_rightpos_tl }
+              }
+          }
+      }
   }
 
+%% #1: column; #2: key; #3: value
+\cs_new_protected_nopar:Npn \__tblr_set_hline_option:nnn #1 #2 #3
+  {
+    \__tblr_spec_gput:nee { hline }
+      { [\int_use:N \c at rownum][#1](\l__tblr_hline_num_tl) / #2 } { #3 }
+  }
+
 \NewTableCommand \firsthline [1] [] { \SetHline [+] {-} { #1, baseline=below } }
 \NewTableCommand \lasthline [1] [] { \SetHline [+] {-} { #1, baseline=above } }
 
@@ -1156,13 +1332,13 @@
   {
     \tl_if_eq:nnTF {#1} {above}
       {
-        \__tblr_prop_gput:nnx { table }
+        \__tblr_prop_gput:nnx { inner }
           { baseline } { \int_eval:n { \c at rownum - 1 } }
       }
       {
         \tl_if_eq:nnT {#1} {below}
           {
-            \__tblr_prop_gput:nnx { table } { baseline } { \int_use:N \c at rownum }
+            \__tblr_prop_gput:nnx { inner } { baseline } { \int_use:N \c at rownum }
           }
       }
   }
@@ -1206,6 +1382,8 @@
 \tl_new:N \l__tblr_vline_dash_tl  % dash style
 \tl_new:N \l__tblr_vline_fg_tl    % dash foreground
 \tl_new:N \l__tblr_vline_wd_tl    % dash width
+\tl_new:N \l__tblr_vline_abovepos_tl % above position
+\tl_new:N \l__tblr_vline_belowpos_tl % below position
 
 \NewTableCommand \rline [2] [] { \SetVline [=] {#2} {#1} }
 
@@ -1267,12 +1445,12 @@
   {
     \tl_clear:N \l__tblr_vline_num_tl
     \tl_set:Nx \l__tblr_vline_count_tl
-      { \__tblr_text_item:ne { vline } { [\int_use:N \c at colnum] / @vline-count } }
+      { \__tblr_spec_item:ne { vline } { [\int_use:N \c at colnum] / @vline-count } }
     %% \l__tblr_vline_count_tl may be empty when colspec has extra |'s
     \int_compare:nNnTF { \l__tblr_vline_count_tl + 0 } = {0}
       {
         \tl_set:Nx \l__tblr_vline_num_tl { 1 }
-        \__tblr_text_gput:nen { vline }
+        \__tblr_spec_gput:nen { vline }
           { [\int_use:N \c at colnum] / @vline-count } { 1 }
       }
       {
@@ -1294,7 +1472,7 @@
   {
     \tl_set:Nx \l__tblr_vline_count_tl
       { \int_eval:n { \l__tblr_vline_count_tl + 1 } }
-    \__tblr_text_gput:nee { vline }
+    \__tblr_spec_gput:nee { vline }
       { [\int_use:N \c at colnum] / @vline-count } { \l__tblr_vline_count_tl }
     \tl_set_eq:NN \l__tblr_vline_num_tl \l__tblr_vline_count_tl
   }
@@ -1306,6 +1484,8 @@
     text .groups:n = { text },
     wd .code:n = \tl_set:Nn \l__tblr_vline_wd_tl { \dim_eval:n {#1} },
     fg .code:n = \tl_set:Nn \l__tblr_vline_fg_tl {#1},
+    abovepos .code:n = \tl_set:Nx \l__tblr_vline_abovepos_tl {#1},
+    belowpos .code:n = \tl_set:Nx \l__tblr_vline_belowpos_tl {#1},
     unknown .code:n = \__tblr_vline_unknown_key:V \l_keys_key_str,
   }
 
@@ -1329,21 +1509,33 @@
     \__tblr_get_childs:nx {#1} { \int_use:N \c at rowcount }
     \clist_map_inline:Nn \l_tblr_childs_clist
       {
-        \__tblr_text_gput:nee { vline }
+        \__tblr_spec_gput:nee { vline }
           { [##1][\int_use:N \c at colnum](\l__tblr_vline_num_tl) / @dash }
           { \l__tblr_vline_dash_tl }
         \tl_if_empty:NF \l__tblr_vline_wd_tl
           {
-            \__tblr_text_gput:nee { vline }
+            \__tblr_spec_gput:nee { vline }
               { [##1][\int_use:N \c at colnum](\l__tblr_vline_num_tl) / wd }
               { \l__tblr_vline_wd_tl }
           }
         \tl_if_empty:NF \l__tblr_vline_fg_tl
           {
-            \__tblr_text_gput:nee { vline }
+            \__tblr_spec_gput:nee { vline }
               { [##1][\int_use:N \c at colnum](\l__tblr_vline_num_tl) / fg }
               { \l__tblr_vline_fg_tl }
           }
+        \tl_if_empty:NF \l__tblr_vline_abovepos_tl
+          {
+            \__tblr_spec_gput:nee { vline }
+              { [##1][\int_use:N \c at colnum](\l__tblr_vline_num_tl) / abovepos }
+              { \l__tblr_vline_abovepos_tl }
+          }
+        \tl_if_empty:NF \l__tblr_vline_belowpos_tl
+          {
+            \__tblr_spec_gput:nee { vline }
+              { [##1][\int_use:N \c at colnum](\l__tblr_vline_num_tl) / belowpos }
+              { \l__tblr_vline_belowpos_tl }
+          }
       }
   }
 
@@ -1440,36 +1632,45 @@
 
 \keys_define:nn { tblr-cell-spec }
   {
-    l .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { halign } {l},
-    c .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { halign } {c},
-    r .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { halign } {r},
-    t .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {t},
-    p .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {t},
-    m .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {m},
-    b .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {b},
-    h .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {h},
-    f .code:n = \__tblr_data_gput:neenn { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { valign} {f},
-    wd .code:n = \__tblr_data_gput:neene { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { width } {#1},
-    bg .code:n = \__tblr_data_gput:neene { cell }
-                  { \int_use:N \c at rownum } { \int_use:N \c at colnum }
-                  { background } {#1},
-    preto .code:n = \__tblr_cell_preto_text:n {#1},
-    appto .code:n = \__tblr_cell_appto_text:n {#1},
-    fg .code:n = \__tblr_cell_preto_text:n { \color{#1} },
-    font .code:n = \__tblr_cell_preto_text:n { #1 \selectfont },
+    halign  .code:n = \__tblr_cell_gput:nn { halign } {#1},
+    valign  .code:n = \__tblr_cell_gput:nn { valign } {#1},
+    j       .meta:n = { halign = j },
+    l       .meta:n = { halign = l },
+    c       .meta:n = { halign = c },
+    r       .meta:n = { halign = r },
+    t       .meta:n = { valign = t },
+    p       .meta:n = { valign = t },
+    m       .meta:n = { valign = m },
+    b       .meta:n = { valign = b },
+    h       .meta:n = { valign = h },
+    f       .meta:n = { valign = f },
+    wd      .code:n = \__tblr_cell_gput:ne { width } {#1},
+    bg      .code:n = \__tblr_cell_gput:ne { background } {#1},
+    fg      .code:n = \__tblr_cell_gput:ne { foreground } {#1},
+    font    .code:n = \__tblr_cell_gput:nn { font } { #1 \selectfont },
+    mode    .code:n = \__tblr_cell_gput:nn { mode } {#1},
+    $       .meta:n = { mode = math },
+    $$      .meta:n = { mode = dmath },
+    cmd     .code:n = \__tblr_cell_gput:nn { cmd } {#1},
+    preto   .code:n = \__tblr_cell_preto_text:n {#1},
+    appto   .code:n = \__tblr_cell_appto_text:n {#1},
     unknown .code:n = \__tblr_cell_unknown_key:V \l_keys_key_str,
   }
 
+\cs_new_protected:Npn \__tblr_cell_gput:nn #1 #2
+  {
+    \__tblr_data_gput:neenn { cell }
+      { \int_use:N \c at rownum } { \int_use:N \c at colnum } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_cell_gput:nn { ne }
+
+\cs_new_protected:Npn \__tblr_cell_gput:nnnn #1 #2 #3 #4
+  {
+    \__tblr_data_gput:nnnnn { cell } {#1} {#2} {#3} {#4}
+  }
+\cs_generate_variant:Nn \__tblr_cell_gput:nnnn
+  { nenn, ennn, eenn, nene, enne, eene }
+
 \tl_new:N \l__tblr_cell_text_tl
 
 \cs_new_protected:Npn \__tblr_cell_preto_text:n #1
@@ -1480,9 +1681,9 @@
 
 \cs_new_protected:Npn \__tblr_cell_preto_text:nnn #1 #2 #3
   {
-    \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_text_item:nn { text } { [#1][#2] } }
+    \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:nn { text } { [#1][#2] } }
     \tl_put_left:Nn \l__tblr_cell_text_tl {#3}
-    \__tblr_text_gput:nnV { text } { [#1][#2] } \l__tblr_cell_text_tl
+    \__tblr_spec_gput:nnV { text } { [#1][#2] } \l__tblr_cell_text_tl
   }
 \cs_generate_variant:Nn \__tblr_cell_preto_text:nnn { nen, enn, een }
 
@@ -1494,9 +1695,9 @@
 
 \cs_new_protected:Npn \__tblr_cell_appto_text:nnn #1 #2 #3
   {
-    \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_text_item:ne { text } { [#1][#2] } }
+    \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:ne { text } { [#1][#2] } }
     \tl_put_right:Nn \l__tblr_cell_text_tl {#3}
-    \__tblr_text_gput:neV { text } { [#1][#2] } \l__tblr_cell_text_tl
+    \__tblr_spec_gput:neV { text } { [#1][#2] } \l__tblr_cell_text_tl
   }
 \cs_generate_variant:Nn \__tblr_cell_appto_text:nnn { nen, enn, een }
 
@@ -1520,13 +1721,13 @@
   {
     \int_compare:nNnT { #1 } > { 1 }
       {
-        \__tblr_prop_gput:nnn {table} {rowspan} {true}
+        \__tblr_prop_gput:nnn { inner } { rowspan } { true }
         \__tblr_data_gput:neenn { cell }
           { \int_use:N \c at rownum } { \int_use:N \c at colnum } { rowspan } {#1}
       }
     \int_compare:nNnT { #2 } > { 1 }
       {
-        \__tblr_prop_gput:nnn {table} {colspan} {true}
+        \__tblr_prop_gput:nnn { inner } { colspan } { true }
         \__tblr_data_gput:neenn { cell }
           { \int_use:N \c at rownum } { \int_use:N \c at colnum } { colspan } {#2}
       }
@@ -1546,16 +1747,33 @@
               }
             \int_compare:nNnF { \l__tblr_i_tl } = { \c at rownum }
               {
-                \__tblr_text_gput:nen { hline }
+                \__tblr_spec_gput:nen { hline }
                   { [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true}
               }
             \int_compare:nNnF { \l__tblr_j_tl } = { \c at colnum }
               {
-                \__tblr_text_gput:nee { vline }
+                \__tblr_spec_gput:nee { vline }
                   { [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true}
               }
           }
       }
+    %% Make continuous borders for multirow cells
+    \tl_set:Nx \l__tblr_n_tl
+      {
+        \int_max:nn
+          {
+            \__tblr_spec_item:ne { vline } { [\int_use:N \c at colnum] / @vline-count }
+          }
+          { 1 }
+      }
+    \int_step_variable:nnNn
+      { \c at rownum } { \int_eval:n { \c at rownum + #1 -1 } } \l__tblr_i_tl
+      {
+        \__tblr_spec_gput:nee { vline }
+          { [\l__tblr_i_tl][\int_use:N \c at colnum](\l__tblr_n_tl) / belowpos } {1}
+        \__tblr_spec_gput:nee { vline }
+          { [\l__tblr_i_tl][\int_eval:n {\c at colnum + #2}](1) / belowpos } {1}
+      }
   }
 \cs_generate_variant:Nn \__tblr_set_span_spec:nn { VV }
 
@@ -1678,53 +1896,63 @@
 
 \keys_define:nn { tblr-column }
   {
-    l .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { halign } {l},
-    c .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { halign } {c},
-    r .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { halign } {r},
-    t .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {t},
-    p .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {t},
-    m .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {m},
-    b .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {b},
-    h .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {h},
-    f .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { valign } {f},
-    bg .code:n = \__tblr_set_key_for_every_column_cell:nnn
-                  { \int_use:N \c at colnum } { background } {#1},
-    fg .code:n = \__tblr_preto_text_for_every_column_cell:n { \color{#1} },
-    font .code:n = \__tblr_preto_text_for_every_column_cell:n { #1 \selectfont },
-    wd .code:n = \__tblr_data_gput:nene { column }
-                   { \int_use:N \c at colnum } { width } { \dim_eval:n {#1} },
-    co .code:n = \__tblr_data_gput:nene { column }
-                   { \int_use:N \c at colnum } { coefficient } {#1},
-    leftsep .code:n = \__tblr_data_gput:nene { column }
-                   { \int_use:N \c at colnum } { leftsep } { \dim_eval:n {#1} },
-    rightsep .code:n = \__tblr_data_gput:nene { column }
-                   { \int_use:N \c at colnum } { rightsep } { \dim_eval:n {#1} },
-    colsep .meta:n = { leftsep = #1, rightsep = #1},
-    leftsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { column }
-                   { \int_use:N \c at colnum } { leftsep } { \dim_eval:n {#1} },
-    rightsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { column }
-                   { \int_use:N \c at colnum } { rightsep } { \dim_eval:n {#1} },
-    colsep+ .meta:n = { leftsep+ = #1, rightsep+ = #1},
-    unknown .code:n = \__tblr_column_unknown_key:V \l_keys_key_str,
+    halign    .code:n = \__tblr_column_gput_cell:nn { halign } {#1},
+    valign    .code:n = \__tblr_column_gput_cell:nn { valign } {#1},
+    j         .meta:n = { halign = j },
+    l         .meta:n = { halign = l },
+    c         .meta:n = { halign = c },
+    r         .meta:n = { halign = r },
+    t         .meta:n = { valign = t },
+    p         .meta:n = { valign = t },
+    m         .meta:n = { valign = m },
+    b         .meta:n = { valign = b },
+    h         .meta:n = { valign = h },
+    f         .meta:n = { valign = f },
+    bg        .code:n = \__tblr_column_gput_cell:nn { background } {#1},
+    fg        .code:n = \__tblr_column_gput_cell:nn { foreground } {#1},
+    font      .code:n = \__tblr_column_gput_cell:nn { font } { #1 \selectfont },
+    mode      .code:n = \__tblr_column_gput_cell:nn { mode } {#1},
+    $         .meta:n = { mode = math },
+    $$        .meta:n = { mode = dmath },
+    cmd       .code:n = \__tblr_column_gput_cell:nn { cmd } {#1},
+    wd        .code:n = \__tblr_column_gput:ne { width } { \dim_eval:n {#1} },
+    co        .code:n = \__tblr_column_gput:ne { coefficient } {#1},
+    preto     .code:n = \__tblr_preto_text_for_every_column_cell:n {#1},
+    appto     .code:n = \__tblr_appto_text_for_every_column_cell:n {#1},
+    leftsep   .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} },
+    rightsep  .code:n = \__tblr_column_gput:ne { rightsep } { \dim_eval:n {#1} },
+    colsep    .meta:n = { leftsep = #1, rightsep = #1},
+    leftsep+  .code:n = \__tblr_column_gadd_dimen:ne
+                          { leftsep } { \dim_eval:n {#1} },
+    rightsep+ .code:n = \__tblr_column_gadd_dimen:ne
+                          { rightsep } { \dim_eval:n {#1} },
+    colsep+   .meta:n = { leftsep+ = #1, rightsep+ = #1},
+    unknown   .code:n = \__tblr_column_unknown_key:V \l_keys_key_str,
   }
 
-%% #1: column number; #2: key; #3: value
-\cs_new_protected:Npn \__tblr_set_key_for_every_column_cell:nnn #1 #2 #3
+%% #1: key; #2: value
+\cs_new_protected:Npn \__tblr_column_gput:nn #1 #2
   {
+    \__tblr_data_gput:nenn { column } { \int_use:N \c at colnum } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_column_gput:nn { ne }
+
+\cs_new_protected:Npn \__tblr_column_gadd_dimen:nn #1 #2
+  {
+    \__tblr_data_gadd_dimen_value:nenn { column }
+      { \int_use:N \c at colnum } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_column_gadd_dimen:nn { ne }
+
+%% #1: key; #2: value
+\cs_new_protected:Npn \__tblr_column_gput_cell:nn #1 #2
+  {
     \int_step_inline:nn { \c at rowcount }
       {
-        \__tblr_data_gput:neenn { cell } {##1} {#1} {#2} {#3}
+        \__tblr_cell_gput:nenn {##1} { \int_use:N \c at colnum } {#1} {#2}
       }
   }
+\cs_generate_variant:Nn \__tblr_column_gput_cell:nn { ne }
 
 \cs_new_protected:Npn \__tblr_preto_text_for_every_column_cell:n #1
   {
@@ -1747,20 +1975,13 @@
 \cs_new_protected:Npn \__tblr_column_unknown_key:n #1
   {
     \regex_match:NnTF \c__tblr_is_number_key_regex {#1}
+      { \__tblr_column_gput:ne { coefficient } {#1} }
       {
-        \__tblr_data_gput:nene { column }
-          { \int_use:N \c at colnum } { coefficient } {#1}
-      }
-      {
         \regex_match:NnTF \c__tblr_is_color_key_regex {#1}
+          { \__tblr_column_gput_cell:nn { background } {#1} }
           {
-            \__tblr_set_key_for_every_column_cell:nnn
-              { \int_use:N \c at colnum } { background } {#1}
-          }
-          {
             \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
-            \__tblr_data_gput:nene { column }
-              { \int_use:N \c at colnum } { width } { \dim_eval:n { \l__tblr_v_tl } }
+            \__tblr_column_gput:ne { width } { \dim_eval:n { \l__tblr_v_tl } }
           }
       }
   }
@@ -1830,55 +2051,76 @@
 
 \keys_define:nn { tblr-row }
   {
-    l .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { halign } {l},
-    c .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { halign } {c},
-    r .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { halign } {r},
-    t .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {t},
-    p .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {t},
-    m .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {m},
-    b .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {b},
-    h .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {h},
-    f .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { valign } {f},
-    bg .code:n = \__tblr_set_key_for_every_row_cell:nnn
-                  { \int_use:N \c at rownum } { background } {#1},
-    fg .code:n = \__tblr_preto_text_for_every_row_cell:n { \color{#1} },
-    font .code:n = \__tblr_preto_text_for_every_row_cell:n { #1 \selectfont },
-    ht .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c at rownum }
-                   { height } { \dim_eval:n {#1} },
-    co .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c at rownum }
-                   { coefficient } {#1},
-    abovesep .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c at rownum }
-                         { abovesep } { \dim_eval:n {#1} },
-    belowsep .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c at rownum }
-                         { belowsep } { \dim_eval:n {#1} },
-    rowsep .meta:n = { abovesep = #1, belowsep = #1},
-    abovesep+ .code:n = \__tblr_data_gadd_dimen_value:nene { row }
-                   { \int_use:N \c at rownum } { abovesep } { \dim_eval:n {#1} },
-    belowsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { row }
-                   { \int_use:N \c at rownum } { belowsep } { \dim_eval:n {#1} },
-    rowsep+ .meta:n = { abovesep+ = #1, belowsep+ = #1},
-    nobreak .code:n = \__tblr_prop_gput:nxx { row }
-                   { [\int_eval:n {\c at rownum - 1}] / nobreak } { true },
-    unknown .code:n = \__tblr_row_unknown_key:V \l_keys_key_str,
+    halign    .code:n = \__tblr_row_gput_cell:nn { halign } {#1},
+    valign    .code:n = \__tblr_row_gput_cell:nn { valign } {#1},
+    j         .meta:n = { halign = j },
+    l         .meta:n = { halign = l },
+    c         .meta:n = { halign = c },
+    r         .meta:n = { halign = r },
+    t         .meta:n = { valign = t },
+    p         .meta:n = { valign = t },
+    m         .meta:n = { valign = m },
+    b         .meta:n = { valign = b },
+    h         .meta:n = { valign = h },
+    f         .meta:n = { valign = f },
+    bg        .code:n = \__tblr_row_gput_cell:nn { background } {#1},
+    fg        .code:n = \__tblr_row_gput_cell:nn { foreground } {#1},
+    font      .code:n = \__tblr_row_gput_cell:nn { font } { #1 \selectfont },
+    mode      .code:n = \__tblr_row_gput_cell:nn { mode } {#1},
+    $         .meta:n = { mode = math },
+    $$        .meta:n = { mode = dmath },
+    cmd       .code:n = \__tblr_row_gput_cell:nn { cmd } {#1},
+    ht        .code:n = \__tblr_row_gput:ne { height } { \dim_eval:n {#1} },
+    co        .code:n = \__tblr_row_gput:ne { coefficient } {#1},
+    preto     .code:n = \__tblr_preto_text_for_every_row_cell:n {#1},
+    appto     .code:n = \__tblr_appto_text_for_every_row_cell:n {#1},
+    abovesep  .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
+    belowsep  .code:n = \__tblr_row_gput:ne { belowsep } { \dim_eval:n {#1} },
+    rowsep    .meta:n = { abovesep = #1, belowsep = #1},
+    abovesep+ .code:n = \__tblr_row_gadd_dimen:ne { abovesep } { \dim_eval:n {#1} },
+    belowsep+ .code:n = \__tblr_row_gadd_dimen:ne { belowsep } { \dim_eval:n {#1} },
+    rowsep+   .meta:n = { abovesep+ = #1, belowsep+ = #1},
+    break     .code:n = \__tblr_row_gput:nn { break } {#1},
+    pagebreak   .meta:n = { break = 1 },
+    nopagebreak .meta:n = { break = -1 },
+    unknown   .code:n = \__tblr_row_unknown_key:V \l_keys_key_str,
   }
 
-%% #1: row number; #2: key; #3: value
-\cs_new_protected:Npn \__tblr_set_key_for_every_row_cell:nnn #1 #2 #3
+%% #1: key; #2: value
+\cs_new_protected:Npn \__tblr_row_gput:nn #1 #2
   {
+    \__tblr_data_gput:nenn { row } { \int_use:N \c at rownum } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_row_gput:nn { ne }
+
+\cs_new_protected:Npn \__tblr_row_gput_above:nn #1 #2
+  {
+    \__tblr_data_gput:nenn { row } { \int_eval:n { \c at rownum - 1 } } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_row_gput_above:nn { ne }
+
+\cs_new_protected:Npn \__tblr_row_gadd_dimen:nn #1 #2
+  {
+    \__tblr_data_gadd_dimen_value:nenn { row } { \int_use:N \c at rownum } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_row_gadd_dimen:nn { ne }
+
+\cs_new_protected:Npn \__tblr_row_gadd_dimen_above:nn #1 #2
+  {
+    \__tblr_data_gadd_dimen_value:nenn { row }
+      { \int_eval:n { \c at rownum - 1 } } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_row_gadd_dimen_above:nn { ne }
+
+%% #1: key; #2: value
+\cs_new_protected:Npn \__tblr_row_gput_cell:nn #1 #2
+  {
     \int_step_inline:nn { \c at colcount }
       {
-        \__tblr_data_gput:neenn { cell } {#1} {##1} {#2} {#3}
+        \__tblr_cell_gput:ennn { \int_use:N \c at rownum } {##1} {#1} {#2}
       }
   }
+\cs_generate_variant:Nn \__tblr_row_gput_cell:nn { ne }
 
 \cs_new_protected:Npn \__tblr_preto_text_for_every_row_cell:n #1
   {
@@ -1905,19 +2147,25 @@
       }
       {
         \regex_match:NnTF \c__tblr_is_color_key_regex {#1}
+          { \__tblr_row_gput_cell:nn { background } {#1} }
           {
-            \__tblr_set_key_for_every_row_cell:nnn
-              { \int_use:N \c at rownum } { background } {#1}
+            \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
+            \__tblr_row_gput:ne { height } { \dim_eval:n { \l__tblr_v_tl } }
           }
-          {
-          \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
-            \__tblr_data_gput:nene { row } { \int_use:N \c at rownum }
-              { height } { \dim_eval:n { \l__tblr_v_tl } }
-          }
       }
   }
 \cs_generate_variant:Nn \__tblr_row_unknown_key:n { V }
 
+\NewTableCommand \pagebreak
+  {
+    \tblr_set_row:nn {} { break = 1 }
+  }
+
+\NewTableCommand \nopagebreak
+  {
+    \tblr_set_row:nn {} { break = -1 }
+  }
+
 %%% --------------------------------------------------------
 %%  \section{Column Types and Row Types}
 %%% --------------------------------------------------------
@@ -2117,6 +2365,7 @@
 \NewColumnRowType { l } { Q[l] }
 \NewColumnRowType { c } { Q[c] }
 \NewColumnRowType { r } { Q[r] }
+\NewColumnRowType { j } { Q[j] }
 
 \NewColumnType { t } [1] { Q[t,wd=#1] }
 \NewColumnType { p } [1] { Q[p,wd=#1] }
@@ -2179,8 +2428,11 @@
       }
       {
         \str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1}
-          { \cs:w tblr_ \g__tblr_column_or_row_tl _type_  #1 \cs_end: }
           {
+            %% Note that #1 may be an active character (see issue #58)
+            \cs:w tblr_ \g__tblr_column_or_row_tl _type_ \token_to_str:N #1 \cs_end:
+          }
+          {
             \msg_error:nnVn { tabularray } { unknown-colrow-type }
               \g__tblr_column_or_row_tl {#1}
             \str_log:c { g_tblr_used_ \g__tblr_column_or_row_tl _types_str }
@@ -2205,43 +2457,102 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Tabularray Environments}
+%%  \section{Set Environments and New Environments}
 %%% --------------------------------------------------------
 
+\tl_new:N \l__tblr_initial_tblr_outer_tl
+\tl_set:Nn \l__tblr_initial_tblr_outer_tl
+  {
+    halign = c, valign = m, headsep = 6pt, footsep = 6pt,
+    presep = 1.5\bigskipamount, postsep = 1.5\bigskipamount,
+  }
+
+%% #1: env name; #2: specifications
+\NewDocumentCommand \SetTblrInner { O{tblr} m }
+  {
+    \tl_put_right:cn { l__tblr_default_ #1 _inner_tl } { , #2 }
+    \ignorespaces
+  }
+\cs_new_eq:NN \SetTblrDefault \SetTblrInner
+
+%% #1: env name; #2: specifications
+\NewDocumentCommand \SetTblrOuter { O{tblr} m }
+  {
+    \tl_put_right:cn { l__tblr_default_ #1 _outer_tl } { , #2 }
+    \ignorespaces
+  }
+
+%% #1: env name
+\NewDocumentCommand \NewTblrEnviron { m }
+  {
+    \tl_new:c { l__tblr_default_ #1 _outer_tl }
+    \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl
+    \tl_new:c { l__tblr_default_ #1 _inner_tl }
+    \NewDocumentEnvironment {#1} { O{c} m +b }
+      {
+        \__tblr_environ_code:nnnn {#1} {##1} {##2} {##3}
+      } { }
+    \ignorespaces
+  }
+
+%% Create tblr and longtblr environments
+\NewTblrEnviron { tblr }
+\NewTblrEnviron { longtblr }
+\SetTblrOuter [ longtblr ] { long }
+\NewTblrEnviron { talltblr }
+\SetTblrOuter [ talltblr ] { tall }
+
 \tl_new:N \l__tblr_env_name_tl
 \bool_new:N \l__tblr_math_mode_bool
 
-\NewDocumentEnvironment { tblr } { O{c} m +b }
+%% Main environment code
+\cs_new_protected:Npn \__tblr_environ_code:nnnn #1 #2 #3 #4
   {
-    \tl_set:Nn \l__tblr_env_name_tl { tblr }
+    \int_gincr:N \g__tblr_table_count_int
+    \tl_set:Nn \l__tblr_env_name_tl {#1}
     \mode_if_math:TF
       { \bool_set_true:N \l__tblr_math_mode_bool }
       { \bool_set_false:N \l__tblr_math_mode_bool }
-    \buildtblr {#1} {#2} {#3}
-  } { }
+    \__tblr_builder:nnn {#2} {#3} {#4}
+  }
 
 %% Read, split and build the table
-
-\cs_new_protected:Npn \buildtblr #1 #2 #3
+\cs_new_protected:Npn \__tblr_builder:nnn #1 #2 #3
   {
-    \mode_leave_vertical:
     \int_gincr:N \g_tblr_level_int
     \__tblr_clear_prop_lists:
-    \__tblr_clear_text_lists:
+    \__tblr_clear_spec_lists:
+    \LogTblrTracing { step = init ~ table ~ outer ~ spec}
+    \__tblr_init_table_outer_spec:
+    \LogTblrTracing { step = parse ~ table ~ options }
+    \__tblr_parse_table_option:n {#1}
+    \LogTblrTracing { outer }
+    \LogTblrTracing { option }
     \__tblr_enable_table_commands:
-    \__tblr_split_table:n { #3 }
+    \LogTblrTracing { step = split ~ table}
+    \__tblr_split_table:n {#3}
     \LogTblrTracing { command }
-    \bool_if:NT \g__tblr_use_intarray_bool { \__tblr_initial_table_data: }
-    \__tblr_initial_table_spec:
-    \LogTblrTracing { table }
-    \__tblr_parse_table_spec:n { #2 }
+    \bool_if:NT \g__tblr_use_intarray_bool { \__tblr_init_table_data: }
+    \LogTblrTracing { step = init ~ table ~ inner ~ spec}
+    \__tblr_init_table_inner_spec:
+    \LogTblrTracing { inner }
+    \LogTblrTracing { step = parse ~ table ~ inner ~ spec}
+    \__tblr_parse_table_spec:n {#2}
+    \LogTblrTracing { step = execute ~ table ~ commands}
     \__tblr_execute_table_commands:
     \__tblr_disable_table_commands:
+    \LogTblrTracing { step = calculate ~ cell ~ and ~ line ~ sizes}
+    \__tblr_enable_content_commands:
     \__tblr_calc_cell_and_line_sizes:
-    \__tblr_build_whole:n { #1 }
+    \LogTblrTracing { step = build ~ the ~ whole ~ table}
+    \__tblr_build_whole:
     \int_gdecr:N \g_tblr_level_int
   }
 
+%%% --------------------------------------------------------
+%%  \section{Split Table Contents}
+%%% --------------------------------------------------------
+
 %% Insert and remove braces for nesting environments inside cells
 %% These make line split and cell split workable
 %% We need to replace N times for N level nestings
@@ -2272,35 +2583,54 @@
     \regex_replace_all:NVN \c__tblr_remove_braces_regex \c__tblr_remove_braces_tl #1
   }
 
+\tl_new:N \l__tblr_body_tl
+\tl_new:N \l__tblr_expand_tl
+\seq_new:N \l__tblr_lines_seq
+
+%% Expand every occurrence of the specified macro once
+%% #1: table content; #2: macro to be expanded
+\cs_new_protected:Npn \__tblr_expand_table_body:nN #1 #2
+  {
+    \tl_clear:N \l__tblr_body_tl
+    \cs_set_protected:Npn \__tblr_expand_table_body_aux:w ##1 #2
+      {
+        \tl_put_right:Nn \l__tblr_body_tl {##1}
+        \peek_meaning:NTF \q_stop
+          { \use_none:n }
+          { \exp_last_unbraced:NV \__tblr_expand_table_body_aux:w #2 }
+      }
+    \__tblr_expand_table_body_aux:w #1 #2 \q_stop
+  }
+
 %% Split table content to cells and store them
 %% #1: table content
-
-\seq_new:N \l_tblr_lines_seq
-
 \cs_new_protected:Npn \__tblr_split_table:n #1
   {
+    \tl_set:Nx \l__tblr_expand_tl { \__tblr_spec_item:nn { outer } { expand } }
+    \tl_set:Nx \l__tblr_expand_tl { \tl_head:N \l__tblr_expand_tl }
+    \tl_if_empty:NTF \l__tblr_expand_tl
+      { \tl_set:Nn \l__tblr_body_tl {#1} }
+      { \exp_args:NnV \__tblr_expand_table_body:nN {#1} \l__tblr_expand_tl }
     \int_zero:N \c at rowcount
     \int_zero:N \c at colcount
-    \__tblr_split_table_to_lines:nN { #1 } \l_tblr_lines_seq
-    \__tblr_split_lines_to_cells:N \l_tblr_lines_seq
+    \__tblr_split_table_to_lines:NN \l__tblr_body_tl \l__tblr_lines_seq
+    \__tblr_split_lines_to_cells:N \l__tblr_lines_seq
   }
 
 %% Split table content to a sequence of lines
-%% #1: table content, #2: resulting sequence of lines
-\cs_new_protected:Npn \__tblr_split_table_to_lines:nN #1 #2
+%% #1: tl with table contents, #2: resulting sequence of lines
+\cs_new_protected:Npn \__tblr_split_table_to_lines:NN #1 #2
   {
-    \tl_set:Nn \l_tmpa_tl { #1 }
-    \__tblr_insert_braces:N \l_tmpa_tl
-    \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpa_tl
+    \__tblr_insert_braces:N #1
+    \seq_set_split:NnV \l_tmpa_seq { \\ } #1
     \seq_clear:N #2
     \seq_map_inline:Nn \l_tmpa_seq
       {
         \tl_if_head_eq_meaning:nNTF {##1} *
           {
-            \tl_set:Nn \l__tblr_b_tl { \SetRow{nobreak} }
+            \tl_set:Nn \l__tblr_b_tl { \SetRow { break = -1 } }
             \tl_set:Nx \l__tblr_c_tl { \tl_tail:n {##1} }
             \tl_trim_spaces:N \l__tblr_c_tl %% Ignore spaces between * and [dimen]
-            \tl_log:N \l__tblr_c_tl
             \tl_if_head_eq_meaning:VNT \l__tblr_c_tl [
               {
                 \tl_put_right:Nn \l__tblr_b_tl { \RowBefore at AddBelowSep }
@@ -2346,16 +2676,21 @@
       {
         \tl_set:Nn \l_tmpa_tl { ##1 }
         \__tblr_remove_braces:N \l_tmpa_tl
+        \__tblr_trim_par_space_tokens:N \l_tmpa_tl
         \int_incr:N \c at colnum
         \__tblr_extract_table_commands:N \l_tmpa_tl
-        \__tblr_text_gput:neV { text } { [#1][\int_use:N \c at colnum] } \l_tmpa_tl
+        \__tblr_trim_par_space_tokens:N \l_tmpa_tl
+        \__tblr_spec_gput:neV { text } { [#1][\int_use:N \c at colnum] } \l_tmpa_tl
         \__tblr_add_multicolumn_empty_cell:
       }
     %% Decrease row count by 1 if the last row has only one empty cell text
     %% We need to do it here since the > or < column type may add text to cells
-    \bool_lazy_and:nnTF
-      { \int_compare_p:nNn {\c at colnum} = {1} }
-      { \tl_if_empty_p:N \l_tmpa_tl }
+    \bool_lazy_all:nTF
+      {
+        { \int_compare_p:nNn {#1} = {\c at rowcount} }
+        { \int_compare_p:nNn {\c at colnum} = {1} }
+        { \tl_if_empty_p:N \l_tmpa_tl }
+      }
       { \int_decr:N \c at rowcount }
       {
         \__tblr_prop_gput:nnx
@@ -2367,6 +2702,15 @@
       }
   }
 
+\regex_const:Nn \c__tblr_trim_left_par_space_regex { ^ \c{par} ? \s * }
+\regex_const:Nn \c__tblr_trim_right_space_par_regex { \s * \c{par} ? $ }
+
+\cs_new_protected:Npn \__tblr_trim_par_space_tokens:N #1
+  {
+    \regex_replace_once:NnN \c__tblr_trim_left_par_space_regex {} #1
+    \regex_replace_once:NnN \c__tblr_trim_right_space_par_regex {} #1
+  }
+
 %% Add empty cells after the \multicolumn span cell
 \cs_new_protected:Npn \__tblr_add_multicolumn_empty_cell:
   {
@@ -2373,7 +2717,7 @@
     \int_step_inline:nn { \l__multicolumn_cell_number_int - 1 }
       {
         \int_incr:N \c at colnum
-        \__tblr_text_gput:nen { text }
+        \__tblr_spec_gput:nen { text }
           { [\int_use:N \c at rownum][\int_use:N \c at colnum] } { }
       }
   }
@@ -2395,7 +2739,7 @@
     \tl_clear:N \l__tblr_saved_table_commands_before_cell_text_tl
     \tl_clear:N \l__tblr_saved_cell_text_after_table_commands_tl
     \int_set:Nn \l__multicolumn_cell_number_int {1}
-    \exp_last_unbraced:NV \__tblr_extract_table_commands_next:w #1 \scan_stop:
+    \exp_last_unbraced:NV \__tblr_extract_table_commands_next:n #1 \q_stop
     \tl_if_empty:NF \l__tblr_saved_table_commands_before_cell_text_tl
       {
         \__tblr_prop_gput:nxV { command }
@@ -2405,26 +2749,26 @@
     \tl_set_eq:NN #1 \l__tblr_saved_cell_text_after_table_commands_tl
   }
 
-%% #1 maybe a single token or multiple tokens given in braces
-\cs_new_protected:Npn \__tblr_extract_table_commands_next:w #1
+%% #1 maybe a single token or multiple tokens from a pair of braces
+\cs_new_protected:Npn \__tblr_extract_table_commands_next:n #1
   {
-    \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 }
+    \tl_if_single_token:nTF {#1}
       {
-        \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 }
-          { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool }
-          { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool }
-        \token_if_eq_meaning:NNTF #1 \multicolumn
-          { \__tblr_extract_multicolumn_command:Nn #1 }
-          { \__tblr_extract_one_table_command:N #1 }
-      }
-      {
-        \tl_if_single_token:nTF {#1}
+        \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 }
           {
-            \token_if_eq_meaning:NNF #1 \scan_stop:
+            \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 }
+              { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool }
+              { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool }
+            \token_if_eq_meaning:NNTF #1 \multicolumn
+              { \__tblr_extract_multicolumn_command:Nn #1 }
+              { \__tblr_extract_one_table_command:N #1 }
+          }
+          {
+            \token_if_eq_meaning:NNF #1 \q_stop
               { \__tblr_save_real_cell_text:w #1 }
           }
-          { \__tblr_save_real_cell_text:w {#1} }
       }
+      { \__tblr_save_real_cell_text:w {#1} }
   }
 
 \cs_new_protected:Npn \__tblr_extract_multicolumn_command:Nn #1 #2
@@ -2469,8 +2813,8 @@
       }
       {
         \bool_if:NTF \l__tblr_table_command_unbrace_next_bool
-          { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:w }
-          { \__tblr_extract_table_commands_next:w }
+          { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:n }
+          { \__tblr_extract_table_commands_next:n }
       }
   }
 
@@ -2477,22 +2821,22 @@
 \cs_new_protected:Npn \__tblr_last_unbraced:Nn #1 #2 { #1 #2 }
 
 %% The outermost set of braces of cell text #1 will be removed
-\cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \scan_stop:
+\cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \q_stop
   {
     \tl_set:Nn \l__tblr_saved_cell_text_after_table_commands_tl {#1}
   }
 
 %%% --------------------------------------------------------
-%%  \section{Initial Table Specifications}
+%%  \section{Initialize Table Inner Specifications}
 %%% --------------------------------------------------------
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_table_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_table_prop
   {
     stretch = 1,
     rulesep = 2pt,
   }
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_rows_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_rows_prop
   {
     abovesep = 2pt,
     belowsep = 2pt,
@@ -2503,7 +2847,7 @@
     @row-lower = 0pt,
   }
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_columns_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_columns_prop
   {
     leftsep = 6pt,
     rightsep = 6pt,
@@ -2512,7 +2856,7 @@
     @col-width = 0pt,
   }
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_cells_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_cells_prop
   {
     halign = l,
     valign = t,
@@ -2522,36 +2866,38 @@
     omit = 0,
   }
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_hlines_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_hlines_prop
   {
     @hline-count = 0,
   }
 
-\prop_gset_from_keyval:Nn \g__tblr_default_tblr_vlines_prop
+\prop_gset_from_keyval:Nn \g__tblr_initial_vlines_prop
   {
     @vline-count = 0,
   }
 
-\cs_new_protected:Npn \__tblr_initial_table_spec:
+\tl_new:N \l__tblr_inner_spec_measure_tl
+\tl_new:N \l__tblr_inner_spec_verb_tl
+
+\cs_new_protected:Npn \__tblr_init_table_inner_spec:
   {
-    \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _table_prop }
+    \prop_map_inline:Nn \g__tblr_initial_table_prop
       {
-        \__tblr_prop_gput:nxn { table } { ##1 } {##2}
+        \__tblr_prop_gput:nxn { inner } { ##1 } {##2}
       }
     \int_step_variable:nNn { \c at rowcount } \l__tblr_i_tl
       {
-        \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _rows_prop }
+        \prop_map_inline:Nn \g__tblr_initial_rows_prop
           {
             \__tblr_data_gput:nVnn { row } \l__tblr_i_tl {##1} {##2}
           }
-        \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _hlines_prop }
+        \prop_map_inline:Nn \g__tblr_initial_hlines_prop
           {
-            \__tblr_text_gput:nen { hline } { [\l__tblr_i_tl] / ##1 } {##2}
+            \__tblr_spec_gput:nen { hline } { [\l__tblr_i_tl] / ##1 } {##2}
           }
         \int_step_variable:nNn { \c at colcount } \l__tblr_j_tl
           {
-            \prop_map_inline:cn
-              { g__tblr_default_ \l__tblr_env_name_tl _cells_prop }
+            \prop_map_inline:Nn \g__tblr_initial_cells_prop
               {
                 \__tblr_data_gput:neeen { cell }
                   { \l__tblr_i_tl } { \l__tblr_j_tl } {##1} {##2}
@@ -2558,61 +2904,55 @@
               }
           }
       }
-    \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _hlines_prop }
+    \prop_map_inline:Nn \g__tblr_initial_hlines_prop
       {
-        \__tblr_text_gput:nen { hline }
+        \__tblr_spec_gput:nen { hline }
           { [\int_eval:n { \c at rowcount + 1}] / ##1 } {##2}
       }
     \int_step_variable:nNn { \c at colcount } \l__tblr_j_tl
       {
-        \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _columns_prop }
+        \prop_map_inline:Nn \g__tblr_initial_columns_prop
           {
             \__tblr_data_gput:nenn { column } { \l__tblr_j_tl } {##1} {##2}
           }
-        \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _vlines_prop }
+        \prop_map_inline:Nn \g__tblr_initial_vlines_prop
           {
-            \__tblr_text_gput:nen { vline } { [\l__tblr_j_tl] / ##1 } {##2}
+            \__tblr_spec_gput:nen { vline } { [\l__tblr_j_tl] / ##1 } {##2}
           }
       }
-    \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _vlines_prop }
+    \prop_map_inline:Nn \g__tblr_initial_vlines_prop
       {
-        \__tblr_text_gput:nen { vline }
+        \__tblr_spec_gput:nen { vline }
           { [\int_eval:n { \c at colcount + 1}] / ##1 } {##2}
       }
-    \keys_set:nv { tblr } { l__tblr_default_ \l__tblr_env_name_tl _tl }
+    \tl_clear:N \l__tblr_inner_spec_measure_tl
+    \tl_clear:N \l__tblr_inner_spec_verb_tl
+    \keys_set:nv { tblr } { l__tblr_default_ \l__tblr_env_name_tl _inner_tl }
   }
 
-\tl_new:N \l__tblr_default_tblr_tl
-
-%% #1: env name; #2: options
-\NewDocumentCommand \SetTabularrayDefault { O{tblr} m }
-  {
-    \tl_put_right:cn { l__tblr_default_ #1 _tl } { , #2 }
-  }
-\cs_new_eq:NN \SetTblrDefault \SetTabularrayDefault
-
 %%% --------------------------------------------------------
-%%  \section{Parse Table Specifications}
+%%> \section{Parse Table Inner Specifications}
 %%% --------------------------------------------------------
 
 \clist_new:N \g__tblr_table_known_keys_clist
 \clist_gset:Nn \g__tblr_table_known_keys_clist
   {
-    long, colspec, rowspec, width, hspan, stretch,
+    colspec, rowspec, width, hspan, vspan, stretch, verb,
     column, row, cell, vline, hline, columns, rows, cells, vlines, hlines,
     leftsep, rightsep, colsep, abovesep, belowsep, rowsep, rulesep,
+    rowhead, rowfoot,
   }
 
-\bool_new:N \l__tblr_long_table_bool
-
 \keys_define:nn { tblr }
   {
-    long .bool_set:N = \l__tblr_long_table_bool,
     colspec .code:n = \__tblr_parse_colrow_spec:nn { column } {#1},
     rowspec .code:n = \__tblr_parse_colrow_spec:nn { row } {#1},
     width .code:n = \__tblr_keys_gput:nx { width } { \dim_eval:n {#1} },
     hspan .code:n = \__tblr_keys_gput:nn { hspan } {#1},
+    vspan .code:n = \__tblr_keys_gput:nn { vspan } {#1},
     stretch .code:n = \__tblr_keys_gput:nn { stretch } {#1},
+    verb   .tl_set:N = \l__tblr_inner_spec_verb_tl,
+    verb  .default:n = lite,
     columns .code:n = \__tblr_set_every_column_aux:n {#1},
     rows    .code:n = \__tblr_set_every_row_aux:n {#1},
     cells   .code:n = \__tblr_set_every_cell_aux:n {#1},
@@ -2625,6 +2965,8 @@
     belowsep .code:n = \tblr_set_every_row:nn { } { belowsep = #1 },
     rowsep .meta:n = { abovesep = #1, belowsep = #1 },
     rulesep .code:n = \__tblr_keys_gput:nn { rulesep } {#1},
+    rowhead .code:n = \__tblr_keys_gput:nn { rowhead } {#1},
+    rowfoot .code:n = \__tblr_keys_gput:nn { rowfoot } {#1},
     unknown .code:n = \__tblr_table_special_key:Vn \l_keys_key_str {#1},
   }
 
@@ -2658,13 +3000,108 @@
       { \__tblr_parse_colrow_spec:nn { column } {#1} }
   }
 
-\cs_new_protected:Npn  \__tblr_keys_gput:nn #1 #2
+\cs_new_protected:Npn \__tblr_keys_gput:nn #1 #2
   {
-    \__tblr_prop_gput:nnn { table } {#1} {#2}
+    \__tblr_prop_gput:nnn { inner } {#1} {#2}
   }
 \cs_generate_variant:Nn \__tblr_keys_gput:nn { nx }
 
 %%% --------------------------------------------------------
+%%  \section{Initialize and Parse Table Outer Specifications}
+%%% --------------------------------------------------------
+
+%% #1: theme names; #2: template and style commands
+\NewDocumentCommand \NewTblrTheme { m +m }
+  {
+    \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2}
+    \ignorespaces
+  }
+
+\cs_new_protected:Npn \__tblr_use_theme:n #1
+  {
+    \ignorespaces
+    \tl_use:c { g__tblr_theme_ #1 _code_tl }
+  }
+
+\cs_new_protected:Npn \__tblr_init_table_outer_spec:
+  {
+    \keys_set:nv { tblr-outer } { l__tblr_default_ \l__tblr_env_name_tl _outer_tl }
+  }
+
+\cs_new_protected:Npn \__tblr_parse_table_option:n #1
+  {
+    \keys_set:nn { tblr-outer } {#1}
+  }
+
+\keys_define:nn { tblr-outer }
+  {
+    long    .code:n = \__tblr_outer_gput_spec:nn { long } { true },
+    tall    .code:n = \__tblr_outer_gput_spec:nn { tall } { true },
+    halign  .code:n = \__tblr_outer_gput_spec:nn { halign } {#1},
+    valign  .code:n = \__tblr_outer_gput_spec:nn { valign } {#1},
+    l       .meta:n = { halign = l },
+    c       .meta:n = { halign = c },
+    r       .meta:n = { halign = r },
+    t       .meta:n = { valign = t },
+    m       .meta:n = { valign = m },
+    b       .meta:n = { valign = b },
+    expand  .code:n = \__tblr_outer_gput_spec:nn { expand } {#1},
+    headsep .code:n = \__tblr_outer_gput_spec:nn { headsep } {#1},
+    footsep .code:n = \__tblr_outer_gput_spec:nn { footsep } {#1},
+    presep  .code:n = \__tblr_outer_gput_spec:nn { presep }  {#1},
+    postsep .code:n = \__tblr_outer_gput_spec:nn { postsep } {#1},
+    theme   .code:n = \__tblr_use_theme:n {#1},
+    caption .code:n = \__tblr_outer_gput_spec:nn { caption } {#1},
+    entry   .code:n = \__tblr_outer_gput_spec:nn { entry } {#1},
+    label   .code:n = \__tblr_outer_gput_spec:nn { label } {#1},
+    unknown .code:n = \__tblr_table_option_key:Vn \l_keys_key_str {#1},
+  }
+
+\cs_new_protected:Npn \__tblr_outer_gput_spec:nn #1 #2
+  {
+    \__tblr_spec_gput:nen { outer } {#1} {#2}
+  }
+
+\regex_const:Nn \c__tblr_option_key_name_regex { ^ [A-Za-z\-] + $ }
+
+\msg_new:nnn { tabularray } { unknown-outer-key }
+  { Unknown ~ outer ~ key ~ name ~ #1! }
+
+\cs_new_protected:Npn \__tblr_table_option_key:nn #1 #2
+  {
+    \regex_match:NnTF \c__tblr_option_key_name_regex {#1}
+      { \msg_error:nnn { tabularray } { unknown-outer-key } {#1} }
+      {
+        \regex_extract_once:NnNT \c__tblr_split_key_name_regex {#1} \l_tmpa_seq
+          {
+            \tl_set:Nx \l__tblr_a_tl { \seq_item:Nn \l_tmpa_seq {2} }
+            \tl_set_rescan:Nnx \l__tblr_b_tl {} { \seq_item:Nn \l_tmpa_seq {3} }
+            \tl_set:Nx \l__tblr_c_tl { \tl_head:N \l__tblr_b_tl }
+            \use:c { __tblr_outer_gput_ \l__tblr_a_tl :Vn } \l__tblr_c_tl {#2}
+          }
+      }
+  }
+\cs_generate_variant:Nn \__tblr_table_option_key:nn { Vn }
+
+\cs_new_protected:Npn \__tblr_outer_gput_note:nn #1 #2
+  {
+    \__tblr_prop_gput:nnn { note } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_outer_gput_note:nn { Vn }
+
+\cs_new_protected:Npn \__tblr_outer_gput_remark:nn #1 #2
+  {
+    \__tblr_prop_gput:nnn { remark } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_outer_gput_remark:nn { Vn }
+
+\cs_new_protected:Npn \__tblr_outer_gput_more:nn #1 #2
+  {
+    \__tblr_prop_gput:nnn { more } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_outer_gput_more:nn { Vn }
+
+%%% --------------------------------------------------------
 %%  \section{Typeset and Calculate Sizes}
 %%% --------------------------------------------------------
 
@@ -2687,7 +3124,7 @@
 
 \cs_new_protected:Npn \__tblr_make_strut_box:
   {
-    \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { table } { stretch } }
+    \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { inner } { stretch } }
     \hbox_set:Nn \l__tblr_strut_ht_box
       { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt }
     \hbox_set:Nn \l__tblr_strut_dp_box
@@ -2725,11 +3162,11 @@
   {
     \dim_zero:N \l__tblr_w_dim
     \tl_set:Nx \l__tblr_n_tl
-      { \__tblr_text_item:ne { vline } { [#2] / @vline-count } }
+      { \__tblr_spec_item:ne { vline } { [#2] / @vline-count } }
     \int_compare:nNnT { \l__tblr_n_tl } > {0}
       {
         \tl_set:Nx \l__tblr_s_tl
-          { \__tblr_prop_item:ne { table } { rulesep } }
+          { \__tblr_prop_item:ne { inner } { rulesep } }
         \int_step_inline:nn { \l__tblr_n_tl }
           {
             \vbox_set_to_ht:Nnn \l__tblr_b_box {1pt}
@@ -2738,7 +3175,7 @@
                   {#1} {#2} {##1} {1pt} {1pt}
               }
             \tl_set:Nx \l__tblr_w_tl { \dim_eval:n { \box_wd:N \l__tblr_b_box } }
-            \__tblr_text_gput_if_larger:nee { vline }
+            \__tblr_spec_gput_if_larger:nee { vline }
               { [#2](##1) / @vline-width } { \l__tblr_w_tl }
             \dim_add:Nn \l__tblr_w_dim { \l__tblr_w_tl }
             \dim_add:Nn \l__tblr_w_dim { \l__tblr_s_tl }
@@ -2745,7 +3182,7 @@
           }
         \dim_add:Nn \l__tblr_w_dim { - \l__tblr_s_tl }
       }
-    \__tblr_text_gput_if_larger:nee { vline }
+    \__tblr_spec_gput_if_larger:nee { vline }
       { [#2]/ @vline-width } { \dim_use:N \l__tblr_w_dim }
   }
 
@@ -2756,10 +3193,10 @@
   {
     \group_begin:
     \tl_set:Nx \l__tblr_w_tl
-      { \__tblr_text_item:ne { vline } { [#1][#2](#3) / wd } }
+      { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / wd } }
     \tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } }
     \tl_set:Nx \l__tblr_d_tl
-      { \__tblr_text_item:ne { vline } { [#1][#2](#3) / @dash } }
+      { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / @dash } }
     \tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl }
     \tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl }
     \exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr at dash
@@ -2768,10 +3205,13 @@
         \xleaders \l__tblr_b_tl \vfil
       }
       {
+        %% When using text as vline, we need to omit abovepos and belowpos.
+        \unskip
         \hbox_set:Nn \l__tblr_d_box { \l__tblr_b_tl }
         \box_set_ht:Nn \l__tblr_d_box {#4}
         \box_set_dp:Nn \l__tblr_d_box {#5}
         \box_use:N \l__tblr_d_box
+        \vss
       }
     \group_end:
   }
@@ -2783,11 +3223,11 @@
   {
     \dim_zero:N \l__tblr_h_dim
     \tl_set:Nx \l__tblr_n_tl
-      { \__tblr_text_item:ne { hline } { [#1] / @hline-count } }
+      { \__tblr_spec_item:ne { hline } { [#1] / @hline-count } }
     \int_compare:nNnT { \l__tblr_n_tl } > {0}
       {
         \tl_set:Nx \l__tblr_s_tl
-          { \__tblr_prop_item:ne { table } { rulesep } }
+          { \__tblr_prop_item:ne { inner } { rulesep } }
         \int_step_inline:nn { \l__tblr_n_tl }
           {
             \hbox_set_to_wd:Nnn \l__tblr_b_box {1pt}
@@ -2797,7 +3237,7 @@
                 \dim_eval:n
                   { \box_ht:N \l__tblr_b_box + \box_dp:N \l__tblr_b_box }
               }
-            \__tblr_text_gput_if_larger:nee { hline }
+            \__tblr_spec_gput_if_larger:nee { hline }
               { [#1](##1) / @hline-height } { \l__tblr_h_tl }
             \dim_add:Nn \l__tblr_h_dim { \l__tblr_h_tl }
             \dim_add:Nn \l__tblr_h_dim { \l__tblr_s_tl }
@@ -2804,7 +3244,7 @@
           }
         \dim_add:Nn \l__tblr_h_dim { - \l__tblr_s_tl }
       }
-    \__tblr_text_gput_if_larger:nee { hline }
+    \__tblr_spec_gput_if_larger:nee { hline }
       { [#1] / @hline-height } { \dim_use:N \l__tblr_h_dim }
   }
 
@@ -2814,10 +3254,10 @@
   {
     \group_begin:
     \tl_set:Nx \l__tblr_w_tl
-      { \__tblr_text_item:ne { hline } { [#1][#2](#3) / wd } }
+      { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / wd } }
     \tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } }
     \tl_set:Nx \l__tblr_d_tl
-      { \__tblr_text_item:ne { hline } { [#1][#2](#3) / @dash } }
+      { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / @dash } }
     \tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl }
     \tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl }
     \exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr at dash
@@ -2893,9 +3333,11 @@
       {
         \int_incr:N \c at rownum
         \int_zero:N \c at colnum
+        \__tblr_update_rowsep_registers:
         \tl_set:Nx \l__tblr_h_tl
-           { \__tblr_data_item:nen { row } { \int_use:N \c at rownum } { height } }
-        \tl_if_empty:NF \l__tblr_h_tl
+          { \__tblr_data_item:nen { row } { \int_use:N \c at rownum } { height } }
+        %% We didn't initialize row heights with -1pt
+        \dim_compare:nNnF { \l__tblr_h_tl } = { 0pt }
           {
             \__tblr_data_gput:nenV { row } { \int_use:N \c at rownum }
               { @row-height } \l__tblr_h_tl
@@ -2903,6 +3345,7 @@
         \int_step_inline:nn { \c at colcount }
           {
             \int_incr:N \c at colnum
+            \__tblr_update_colsep_registers:
             \__tblr_measure_cell_update_sizes:nnNNNN
               { \int_use:N \c at rownum }
               { \int_use:N \c at colnum }
@@ -2912,8 +3355,33 @@
               \g__tblr_cell_foot_dim
           }
       }
+    \int_step_inline:nn { \c at colcount }
+      {
+        \tl_set:Nx \l__tblr_w_tl
+          { \__tblr_data_item:nen { column } {##1} { width } }
+        \dim_compare:nNnF { \l__tblr_w_tl } < { 0pt }
+          {
+            \__tblr_data_gput:nenV { column } {##1} { @col-width } \l__tblr_w_tl
+          }
+      }
   }
 
+\cs_new_protected:Npn \__tblr_update_rowsep_registers:
+  {
+    \dim_set:Nn \abovesep
+      { \__tblr_data_item:nen { row } { \int_use:N \c at rownum } { abovesep } }
+    \dim_set:Nn \belowsep
+      { \__tblr_data_item:nen { row } { \int_use:N \c at rownum } { belowsep } }
+  }
+
+\cs_new_protected:Npn \__tblr_update_colsep_registers:
+  {
+    \dim_set:Nn \leftsep
+      { \__tblr_data_item:nen { column } { \int_use:N \c at colnum } { leftsep } }
+    \dim_set:Nn \rightsep
+      { \__tblr_data_item:nen { column } { \int_use:N \c at colnum } { rightsep } }
+  }
+
 %% Measure and update natural dimensions of the row/column/cell
 %% #1: row number; #2 column number; #3: width dimension;
 %% #4: total height dimension; #5: head dimension; #6: foot dimension
@@ -2920,7 +3388,9 @@
 \cs_new_protected:Npn \__tblr_measure_cell_update_sizes:nnNNNN #1 #2 #3 #4 #5 #6
   {
     \__tblr_get_cell_alignments:nn {#1} {#2}
+    \__tblr_save_counters:n { trial }
     \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} }
+    \__tblr_restore_counters:n { trial }
     \__tblr_update_cell_size:nnNNNN {#1} {#2} #3 #4 #5 #6
     \__tblr_update_row_size:nnNNN {#1} {#2} #4 #5 #6
     \__tblr_update_col_size:nN {#2} #3
@@ -2939,6 +3409,14 @@
       { \__tblr_get_cell_text_real:nn { #1 } { #2 } }
   }
 
+\tl_new:N \l__tblr_cell_fg_tl
+\tl_new:N \l__tblr_cell_cmd_tl
+\tl_new:N \l__tblr_cell_mode_tl
+\bool_new:N \l__tblr_cell_math_mode_bool
+\tl_const:Nn \l__tblr_cell_math_style_tl  { \relax }
+\tl_const:Nn \l__tblr_cell_imath_style_tl { \textstyle }
+\tl_const:Nn \l__tblr_cell_dmath_style_tl { \displaystyle }
+
 %% Get cell text, #1: row number, #2: column number
 %% If the width of the cell is not set, split it with \\ and compute the width
 %% Therefore we always get a vbox for any cell
@@ -2945,7 +3423,32 @@
 \cs_new_protected:Npn \__tblr_get_cell_text_real:nn #1 #2
   {
     \group_begin:
-    \tl_set:Nx \l__tblr_c_tl { \__tblr_text_item:ne { text } {[#1][#2]} }
+    \tl_set:Nx \l__tblr_cell_cmd_tl
+      { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } }
+    \tl_if_empty:NTF \l__tblr_cell_cmd_tl
+      { \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} } }
+      {
+        \tl_set:Nx \l__tblr_c_tl { { \__tblr_spec_item:ne { text } {[#1][#2]} } }
+        \tl_put_left:NV \l__tblr_c_tl \l__tblr_cell_cmd_tl
+      }
+    \tl_set:Nx \l__tblr_cell_mode_tl
+      { \__tblr_data_item:neen { cell } {#1} {#2} { mode } }
+    \tl_if_empty:NT \l__tblr_cell_mode_tl
+      {
+        \bool_if:NTF \l__tblr_math_mode_bool
+          { \tl_set:Nn \l__tblr_cell_mode_tl { math } }
+          { \tl_set:Nn \l__tblr_cell_mode_tl { text } }
+      }
+    \tl_if_eq:NnTF \l__tblr_cell_mode_tl { text }
+      { \bool_set_false:N \l__tblr_cell_math_mode_bool }
+      {
+        \bool_set_true:N \l__tblr_cell_math_mode_bool
+        \tl_put_left:Nv \l__tblr_c_tl
+          { l__tblr_cell_ \l__tblr_cell_mode_tl _style_tl }
+        \tl_put_left:Nn \l__tblr_c_tl { $ }
+        \tl_put_right:Nn \l__tblr_c_tl { $ }
+      }
+    \tl_set:Nx \l__tblr_f_tl { \__tblr_data_item:neen { cell } {#1} {#2} { font } }
     \tl_set:Nx \l__tblr_w_tl
       { \__tblr_data_item:neen { cell } {#1} {#2} { width } }
     \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % cell width unset
@@ -2959,35 +3462,80 @@
       }
     \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % column width unset
       {
-        \bool_if:NTF \l__tblr_math_mode_bool
+        \bool_if:NTF \l__tblr_cell_math_mode_bool
           {
-            \hbox_set:Nn \l_tmpa_box { $\l__tblr_c_tl$ }
+            \hbox_set:Nn \l_tmpa_box { \l__tblr_c_tl }
             \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
           }
           {
-            \tl_set_eq:NN \l_tmpb_tl \l__tblr_c_tl
-            \__tblr_insert_braces:N \l_tmpb_tl
-            \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpb_tl
-            \tl_set:Nn \l__tblr_w_tl { 0pt }
-            \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl
-              {
-                \__tblr_remove_braces:N \l_tmpa_tl
-                \hbox_set:Nn \l_tmpa_box { \l_tmpa_tl }
-                \tl_set:Nx \l__tblr_w_tl
-                  { \dim_max:nn { \l__tblr_w_tl } { \box_wd:N \l_tmpa_box } }
-              }
+            \__tblr_get_cell_size_with_box:
           }
       }
+    \tl_set:Nx \l__tblr_cell_fg_tl
+      { \__tblr_data_item:neen { cell } {#1} {#2} { foreground } }
+    \tl_put_left:NV \l__tblr_c_tl \l__tblr_f_tl
     \__tblr_get_vcell_and_sizes:NN \l__tblr_c_tl \l__tblr_w_tl
     \group_end:
   }
 
+\cs_new_protected:Npn \__tblr_get_cell_size_with_box:
+  {
+    \__tblr_save_counters:n { cell }
+    \tl_if_eq:NnTF \l__tblr_inner_spec_measure_tl { vbox }
+      { \__tblr_get_cell_size_with_vbox: }
+      { \__tblr_get_cell_size_with_hbox: }
+    \__tblr_restore_counters:n { cell }
+  }
+
+%% Varwidth won't work as expected when \color command occurs in it,
+%% and we can not fix this problem with \leavevmode command.
+%% See https://tex.stackexchange.com/q/460489.
+%% But we need to use \color command for fg option,
+%% or users may use it in the middle of the cell text,
+%% so we have redefine \color command and disable it before measuring cell.
+
+\NewDocumentCommand \__tblr_fake_color_command:w { o m } { }
+
+\cs_new_protected:Npn \__tblr_get_cell_size_with_vbox:
+  {
+    \hbox_set:Nn \l_tmpa_box
+      {
+        \cs_set_eq:NN \color \__tblr_fake_color_command:w
+        \begin{varwidth}{\paperwidth}
+           \l__tblr_f_tl
+           \__tblr_rescan_cell_tokens:N \l__tblr_c_tl
+        \end{varwidth}
+      }
+    \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
+  }
+
+\cs_new_protected:Npn \__tblr_get_cell_size_with_hbox:
+  {
+    \tl_set_eq:NN \l_tmpb_tl \l__tblr_c_tl
+    \__tblr_insert_braces:N \l_tmpb_tl
+    \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpb_tl
+    \tl_set:Nn \l__tblr_w_tl { 0pt }
+    \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl
+      {
+        \__tblr_remove_braces:N \l_tmpa_tl
+        \hbox_set:Nn \l_tmpa_box
+          {
+            \l__tblr_f_tl
+            \__tblr_rescan_cell_tokens:N \l_tmpa_tl
+          }
+        \tl_set:Nx \l__tblr_w_tl
+          { \dim_max:nn { \l__tblr_w_tl } { \box_wd:N \l_tmpa_box } }
+      }
+  }
+
 %% #1: cell text; #2: box width
 \cs_new_protected:Npn \__tblr_get_vcell_and_sizes:NN #1 #2
   {
     \group_begin:
-    \vbox_set_top:Nn \l_tmpa_box { \__tblr_make_vcell_text:nN #1 #2 }
-    \vbox_set:Nn \l_tmpb_box { \__tblr_make_vcell_text:nN #1 #2 }
+    \__tblr_save_counters:n { cell }
+    \vbox_set_top:Nn \l_tmpa_box { \__tblr_make_vcell_text:NN #1 #2 }
+    \__tblr_restore_counters:n { cell }
+    \vbox_set:Nn \l_tmpb_box { \__tblr_make_vcell_text:NN #1 #2 }
     \dim_gset:Nn \g__tblr_cell_wd_dim { \box_wd:N \l_tmpb_box }
     \dim_gset:Nn \g__tblr_cell_ht_dim
       { \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box }
@@ -3029,22 +3577,40 @@
     \group_end:
   }
 
-\cs_new_eq:NN \__tlbr_halign_l: \raggedright
-\cs_new_eq:NN \__tlbr_halign_c: \centering
-\cs_new_eq:NN \__tlbr_halign_r: \raggedleft
-
 %% #1: cell text; #2: box width
-\cs_new_protected:Npn \__tblr_make_vcell_text:nN #1 #2
+%% All halign commands are defined at the beginning of the file
+\cs_new_protected:Npn \__tblr_make_vcell_text:NN #1 #2
   {
     \dim_set:Nn \tex_hsize:D { #2 }
     \@arrayparboxrestore
-    \cs:w __tlbr_halign_ \g__tblr_cell_halign_tl : \cs_end:
+    \cs:w __tblr_halign_command_ \g__tblr_cell_halign_tl : \cs_end:
     \mode_leave_vertical:
     \box_use:N \l__tblr_strut_ht_box
-    \bool_if:NTF \l__tblr_math_mode_bool { $#1$ } { #1 }
+    \tl_if_empty:NF \l__tblr_cell_fg_tl { \exp_args:NV \color \l__tblr_cell_fg_tl }
+    \bool_if:NTF \l__tblr_cell_math_mode_bool
+      { #1 }
+      { \__tblr_rescan_cell_tokens:N #1 }
     \box_use:N \l__tblr_strut_dp_box
   }
 
+%% When using verb option, there is an end-of-line character at the end.
+%% This character causes extra horizontal space at the end when "measure=hbox",
+%% or causes extra vertical space at the end with "measure=vbox".
+%% Therefore we have to use an \empty to remove it.
+%% See https://tex.stackexchange.com/q/213659
+\cs_new_protected:Npn \__tblr_rescan_cell_tokens:N #1
+  {
+    \tl_if_empty:NTF \l__tblr_inner_spec_verb_tl
+      { #1 }
+      {
+        %% insert space characters after some control sequences first (issue #112)
+        \regex_replace_all:nnN { (\c{[A-Za-z]*}) ([A-Za-z]) } { \1 \  \2 } #1
+        \regex_replace_all:nnN { . } { \c{string} \0 } #1
+        \tl_set:Nx #1 { #1 \noexpand \empty }
+        \exp_args:NV \tex_scantokens:D #1
+      }
+  }
+
 %% #1: total height dimension; #2: head dimension; #3: foot dimension;
 %% #4: tl for resulting upper size; #5: tl for resulting lower size
 
@@ -3238,7 +3804,7 @@
 
 \cs_new_protected:Npn \__tblr_collect_extendable_column_width:
   {
-    \tl_set:Nx \l_tmpa_tl { \__tblr_prop_item:nn {table} {width} }
+    \tl_set:Nx \l_tmpa_tl { \__tblr_prop_item:nn { inner } { width } }
     \tl_if_empty:NTF \l_tmpa_tl
       { \dim_set_eq:NN \l__column_target_dim \linewidth }
       { \dim_set:Nn \l__column_target_dim { \l_tmpa_tl } }
@@ -3271,7 +3837,7 @@
           }
           { \dim_sub:Nn \l__column_target_dim { \l__tblr_a_tl } }
         \tl_set:Nx \l__tblr_a_tl
-          { \__tblr_text_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } }
+          { \__tblr_spec_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } }
         \tl_set:Nx \l__tblr_b_tl
           { \__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep } }
         \tl_set:Nx \l__tblr_c_tl
@@ -3281,7 +3847,7 @@
       }
     \tl_set:Nx \l__tblr_a_tl
       {
-        \__tblr_text_item:ne { vline }
+        \__tblr_spec_item:ne { vline }
           { [\int_eval:n {\c at colcount + 1}] / @vline-width }
       }
     \tl_if_empty:NF \l__tblr_a_tl
@@ -3290,7 +3856,8 @@
   }
 
 %% If all columns have negative coefficients and small natural widths,
-%% \l__column_coefficient_prop will be empty after one or more rounds
+%% \l__column_coefficient_prop will be empty after one or more rounds.
+%% We reset @row-height, etc for \linewidth graphics in X columns (issue #80)
 \cs_new_protected:Npn \__tblr_adjust_extendable_column_width:
   {
     \bool_while_do:nn
@@ -3305,6 +3872,14 @@
         \__tblr_data_gput:nnne { column } {##1} { width } {##2}
         \__tblr_data_gput:nnnn { column } {##1} { @col-width } { 0pt }
       }
+    \int_step_inline:nn { \c at rowcount }
+      {
+        \__tblr_data_gput:nnnn { row } {##1} { @row-height } { 0pt }
+        \__tblr_data_gput:nnnn { row } {##1} { @row-head } { 0pt }
+        \__tblr_data_gput:nnnn { row } {##1} { @row-foot } { 0pt }
+        \__tblr_data_gput:nnnn { row } {##1} { @row-upper } { 0pt }
+        \__tblr_data_gput:nnnn { row } {##1} { @row-lower } { 0pt }
+      }
     \__tblr_calculate_cell_sizes:
   }
 
@@ -3378,11 +3953,11 @@
 
 \cs_new_protected:Npn \__tblr_adjust_sizes_for_span_cells:
   {
-    \__tblr_prop_if_in:nnT {table} {colspan}
+    \__tblr_prop_if_in:nnT { inner } { colspan }
       {
         \__tblr_collect_column_widths_skips:
         \str_if_eq:xnTF
-          { \__tblr_prop_item:ne {table} {hspan} } {minimal}
+          { \__tblr_prop_item:ne { inner } { hspan } } { minimal }
           {
             \__tblr_set_span_widths_from_column_widths:
           }
@@ -3393,12 +3968,12 @@
         \LogTblrTracing { column }
         \__tblr_calculate_cell_sizes:
       }
-    \__tblr_prop_if_in:nnT {table} {rowspan}
+    \__tblr_prop_if_in:nnT { inner } { rowspan }
       {
         \__tblr_collect_row_heights_skips:
         \__tblr_collect_span_heights:
         \__tblr_set_row_heights_from_span_heights:
-        \LogTblrTracing {row}
+        \LogTblrTracing { row }
       }
   }
 
@@ -3421,7 +3996,7 @@
                     \__tblr_data_item:nen { column }
                       { \int_eval:n { \l__tblr_j_tl - 1 } } { rightsep }
                     +
-                    \__tblr_text_item:ne { vline }
+                    \__tblr_spec_item:ne { vline }
                       { [\l__tblr_j_tl] / @vline-width }
                     +
                     \__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep }
@@ -3453,7 +4028,7 @@
                     \__tblr_data_item:nen { row }
                       { \int_eval:n {\l__tblr_i_tl - 1} } { belowsep }
                     +
-                    \__tblr_text_item:ne { hline }
+                    \__tblr_spec_item:ne { hline }
                       { [\l__tblr_i_tl] / @hline-height }
                     +
                     \__tblr_data_item:nen { row } { \l__tblr_i_tl } { abovesep }
@@ -3585,10 +4160,21 @@
 %% Compute and set column widths from span widths
 \cs_new_protected:Npn \__tblr_set_column_widths_from_span_widths:
   {
-    \__tblr_calc_item_sizes_from_span_sizes:xNN
-      { \int_use:N \c at colcount }
-      \l__tblr_col_item_skip_size_prop
-      \l__tblr_col_span_size_prop
+    \str_if_eq:xnTF
+      { \__tblr_prop_item:ne { inner } { hspan } }
+      { even }
+      {
+        \__tblr_distribute_span_sizes_even:xNN
+          { \int_use:N \c at colcount }
+          \l__tblr_col_item_skip_size_prop
+          \l__tblr_col_span_size_prop
+      }
+      {
+        \__tblr_distribute_span_sizes_default:xNN
+          { \int_use:N \c at colcount }
+          \l__tblr_col_item_skip_size_prop
+          \l__tblr_col_span_size_prop
+      }
     \__tblr_set_all_column_widths:
   }
 
@@ -3595,10 +4181,21 @@
 %% Compute and set row heights from span heights
 \cs_new_protected:Npn \__tblr_set_row_heights_from_span_heights:
   {
-    \__tblr_calc_item_sizes_from_span_sizes:xNN
-      { \int_use:N \c at rowcount }
-      \l__tblr_row_item_skip_size_prop
-      \l__tblr_row_span_size_prop
+    \str_if_eq:xnTF
+      { \__tblr_prop_item:ne { inner } { vspan } }
+      { even }
+      {
+        \__tblr_distribute_span_sizes_even:nNN
+          { \int_use:N \c at rowcount }
+          \l__tblr_row_item_skip_size_prop
+          \l__tblr_row_span_size_prop
+      }
+      {
+        \__tblr_distribute_span_sizes_default:xNN
+          { \int_use:N \c at rowcount }
+          \l__tblr_row_item_skip_size_prop
+          \l__tblr_row_span_size_prop
+      }
     \__tblr_set_all_row_heights:
   }
 
@@ -3605,7 +4202,7 @@
 %% See page 245 in Chapter 22 of TeXbook
 %% #1: total number of items
 %% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes
-\cs_new_protected:Npn \__tblr_calc_item_sizes_from_span_sizes:nNN #1 #2 #3
+\cs_new_protected:Npn \__tblr_distribute_span_sizes_default:nNN #1 #2 #3
   {
     \int_step_variable:nNn { #1 } \l__tblr_j_tl
       {
@@ -3656,14 +4253,60 @@
       }
     \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 }
   }
-\cs_generate_variant:Nn \__tblr_calc_item_sizes_from_span_sizes:nNN { x }
+\cs_generate_variant:Nn \__tblr_distribute_span_sizes_default:nNN { x }
 
+%% #1: total number of items
+%% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes
+\cs_new_protected:Npn \__tblr_distribute_span_sizes_even:nNN #1 #2 #3
+  {
+    \prop_clear:N \l_tmpa_prop
+    \prop_map_inline:Nn #3
+      {
+        \__tblr_get_span_from_to:w ##1
+        \dim_set:Nn \l_tmpa_dim {##2}
+        \dim_sub:Nn \l_tmpa_dim { \prop_item:Ne #2 { item[\l__tblr_a_tl] } }
+        \int_step_inline:nnn { \l__tblr_a_tl + 1 } { \l__tblr_b_tl }
+          {
+            \dim_sub:Nn \l_tmpa_dim
+              {
+                \prop_item:Ne #2 { skip[####1] } + \prop_item:Nn #2 { item[####1] }
+              }
+          }
+        \__tblr_do_if_tracing:nn { cellspan }
+          {
+            \tl_log:x { \l__tblr_a_tl -> \l__tblr_b_tl : ~ \dim_use:N \l_tmpa_dim }
+          }
+        \dim_compare:nNnT {\l_tmpa_dim} > {0pt}
+          {
+            \tl_set:Nx \l_tmpa_tl
+              { \dim_eval:n { \l_tmpa_dim / (\l__tblr_b_tl - \l__tblr_a_tl + 1) } }
+            \int_step_inline:nnn { \l__tblr_a_tl } { \l__tblr_b_tl }
+              {
+                \__tblr_put_if_larger:NnV \l_tmpa_prop {####1} \l_tmpa_tl
+              }
+          }
+      }
+    \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N \l_tmpa_prop }
+    \prop_map_inline:Nn \l_tmpa_prop
+      {
+        \__tblr_add_dimen_value:Nnn #2 {item[##1]} {##2}
+      }
+    \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 }
+  }
+\cs_generate_variant:Nn \__tblr_distribute_span_sizes_even:nNN { x }
+
+\cs_new_protected:Npn \__tblr_get_span_from_to:w (#1-#2)
+  {
+    \tl_set:Nn \l__tblr_a_tl {#1}
+    \tl_set:Nn \l__tblr_b_tl {#2}
+  }
+
 \cs_new_protected:Npn \__tblr_set_all_column_widths:
   {
     \int_step_variable:nNn { \c at colcount } \l__tblr_j_tl
       {
         \__tblr_data_gput:nene { column }
-          { \l__tblr_j_tl } { @col-width }
+          { \l__tblr_j_tl } { width }
           { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[\l__tblr_j_tl] } }
       }
   }
@@ -3690,12 +4333,6 @@
       }
   }
 
-\cs_new_protected:Npn \__tblr_get_span_key_row_col:w [#1][#2]
-  {
-    \tl_set:Nn \l__tblr_i_tl {#1}
-    \tl_set:Nn \l__tblr_j_tl {#2}
-  }
-
 %% Compute and set span widths from column widths
 \cs_new_protected:Npn \__tblr_set_span_widths_from_column_widths:
   {
@@ -3725,8 +4362,8 @@
 %% Cell is spanned from col #1 to col #2, #3 is the return dim
 \cs_new_protected:Npn \__tblr_calc_span_widths:nnN #1 #2 #3
   {
-    \dim_zero:N #3
-    \int_step_inline:nnn { #1 } { #2 }
+    \dim_set:Nn #3 { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#1] } }
+    \int_step_inline:nnn { #1 + 1 } { #2 }
       {
         \tl_set:Nx \l_tmpa_tl
           { \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] } }
@@ -3738,75 +4375,1076 @@
 \cs_generate_variant:Nn \__tblr_calc_span_widths:nnN { xxN }
 
 %%% --------------------------------------------------------
-%%  \section{Build the Whole Table}
+%%> \section{Header and Footer Styles}
 %%% --------------------------------------------------------
 
-\tl_new:N \__tlbr_vbox_align_tl
-\tl_const:Nn \__tlbr_vbox_t_tl {t}
-\tl_const:Nn \__tlbr_vbox_m_tl {m}
-\tl_const:Nn \__tlbr_vbox_c_tl {c}
-\tl_const:Nn \__tlbr_vbox_b_tl {b}
+\prop_new:N \l__tblr_element_styles_prop
 
-\box_new:N \l__tblr_table_box
+\cs_new_protected:Npn \__tblr_style_put:nn #1 #2
+  {
+    \prop_put:Nnn \l__tblr_element_styles_prop {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_style_put:nn { nV, ne, en }
 
-%% #1: table alignment
-\cs_new_protected:Npn \__tblr_build_whole:n #1
+\cs_new:Npn \__tblr_style_item:n #1
   {
-    \bool_if:NTF \l__tblr_long_table_bool
-      { \__tblr_build_long_table:n {#1} }
-      { \__tblr_build_short_table:n {#1} }
+    \prop_item:Nn \l__tblr_element_styles_prop {#1}
   }
 
-\dim_new:N \l__tblr_remain_height_dim
-\tl_new:N \l__tblr_long_from_tl
+\cs_new_protected:Npn \__tblr_style_log:
+  {
+    \prop_log:N \l__tblr_element_styles_prop
+  }
 
-\cs_new_protected:Npn \__tblr_build_long_table:n #1
+\tl_new:N \l__tblr_element_name_tl
+\tl_new:N \l__tblr_element_styles_tl
+
+%% #1: list of element names; #2: element styles
+\NewDocumentCommand \SetTblrStyle { m +m }
   {
-    %\dim_log:N \pagegoal
-    %\dim_log:N \pagetotal
-    \dim_set:Nn \l__tblr_remain_height_dim { \pagegoal - \pagetotal }
-    \tl_set:Nn \l__tblr_long_from_tl {1}
-    \int_step_variable:nNn { \c at rowcount } \l__tblr_i_tl
+    \tl_set:Nn \l__tblr_element_styles_tl {#2}
+    \keys_set:nn { tblr-element } {#1}
+    \ignorespaces
+  }
+
+\keys_define:nn { tblr-element }
+  {
+    head    .meta:n = { firsthead, middlehead, lasthead },
+    foot    .meta:n = { firstfoot, middlefoot, lastfoot },
+    unknown .code:n = \__tblr_set_element_styles:V \l_keys_key_str,
+  }
+
+\cs_new_protected:Npn \__tblr_set_element_styles:n #1
+  {
+    \tl_set:Nn \l__tblr_element_name_tl {#1}
+    \keys_set:nV { tblr-style } \l__tblr_element_styles_tl
+  }
+\cs_generate_variant:Nn \__tblr_set_element_styles:n { V }
+
+\keys_define:nn { tblr-style }
+  {
+    halign  .code:n = \__tblr_element_gput_style:nn { halign } {#1},
+    l       .meta:n = { halign = l },
+    c       .meta:n = { halign = c },
+    r       .meta:n = { halign = r },
+    fg      .code:n = \__tblr_element_gput_style:nn { fg } {#1},
+    font    .code:n = \__tblr_element_gput_style:nn { font } {#1},
+    hang    .code:n = \__tblr_element_gput_style:nn { hang } {#1},
+    indent  .code:n = \__tblr_element_gput_style:nn { indent } {#1},
+    unknown .code:n = \__tblr_element_unknown_key:Vn \l_keys_key_str {#1},
+  }
+
+\cs_new_protected:Npn \__tblr_element_gput_style:nn #1 #2
+  {
+    \__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2}
+  }
+
+\cs_new_protected:Npn \__tblr_element_unknown_key:nn #1 #2
+  {
+    \regex_match:NnTF \c__tblr_is_color_key_regex {#1}
+      { \__tblr_style_put:en { \l__tblr_element_name_tl / fg } {#1} }
       {
-        \dim_set:Nn \l_tmpa_dim
+        %% unknown key name has been changed to string in \l_keys_key_str
+        \tl_set_rescan:Nnn \l__tblr_f_tl {} {#1}
+        \tl_if_head_eq_catcode:VNTF \l__tblr_f_tl \scan_stop:
           {
-            \__tblr_text_item:ne { hline } { [\l__tblr_i_tl] / @hline-height }
+            \__tblr_style_put:en { \l__tblr_element_name_tl / font } \l__tblr_f_tl
+          }
+          {
+            \__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2}
+          }
+      }
+  }
+\cs_generate_variant:Nn \__tblr_element_unknown_key:nn { Vn }
+
+%%% --------------------------------------------------------
+%%> \section{Helper Functions for Templates}
+%%% --------------------------------------------------------
+
+\tl_new:N \l__tblr_template_name_tl
+\tl_new:N \l__tblr_template_code_tl
+
+\keys_define:nn { tblr-def-template }
+  {
+    unknown .code:n = \__tblr_def_template:V \l_keys_key_str,
+  }
+
+%% #1: head/foot element; #2: template name; #3: template code
+%% If the template name = default, we enable the template at once
+%% Otherwise, we may enable the template by using \SetTblrTemplate command
+\NewDocumentCommand \DefTblrTemplate { m m +m }
+  {
+    \tl_set:Nn \l__tblr_template_name_tl {#2}
+    \tl_set:Nn \l__tblr_template_code_tl {#3}
+    \keys_set:nn { tblr-def-template } {#1}
+    \ignorespaces
+  }
+
+\cs_new_protected:Npn \__tblr_def_template:n #1
+  {
+    \tl_set_eq:cN { l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl }
+      \l__tblr_template_code_tl
+  }
+\cs_generate_variant:Nn \__tblr_def_template:n { V }
+
+\keys_define:nn { tblr-set-template }
+  {
+    unknown .code:n = \__tblr_set_template:V \l_keys_key_str,
+  }
+
+%% #1: head/foot element; #2: template name
+\NewDocumentCommand \SetTblrTemplate { m m }
+  {
+    \tl_set:Nn \l__tblr_template_name_tl {#2}
+    \keys_set:nn { tblr-set-template } {#1}
+    \ignorespaces
+  }
+
+\cs_new_protected:Npn \__tblr_set_template:n #1
+  {
+    \tl_set_eq:cc { l__tblr_template_ #1 _default_tl }
+      { l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl }
+  }
+\cs_generate_variant:Nn \__tblr_set_template:n { V }
+
+\NewExpandableDocumentCommand \GetTblrStyle { m m }
+  {
+    \__tblr_style_item:n { #1 / #2 }
+  }
+
+\NewDocumentCommand \UseTblrFont { m }
+  {
+    \GetTblrStyle {#1} { font } \selectfont
+  }
+
+\tl_new:N \l__tblr_use_color_tl
+
+\NewDocumentCommand \UseTblrColor { m }
+  {
+    \tl_set:Nx \l__tblr_use_color_tl { \GetTblrStyle {#1} { fg } }
+    \tl_if_empty:NF \l__tblr_use_color_tl { \color { \l__tblr_use_color_tl } }
+  }
+
+%% All halign commands are defined at the beginning of the file
+\NewDocumentCommand \UseTblrAlign { m }
+  {
+    \use:c { __tblr_halign_command_ \GetTblrStyle {#1} { halign } : }
+  }
+
+\tl_new:N \l__tblr_use_hang_tl
+
+\NewDocumentCommand \UseTblrHang { m }
+  {
+    \tl_set:Nx \l__tblr_use_hang_tl { \GetTblrStyle {#1} { hang } }
+    \tl_if_empty:NF \l__tblr_use_hang_tl
+      {
+        \tl_put_left:Nn \l__tblr_use_hang_tl
+          { \hangafter = 1 \relax \hangindent = }
+        \tl_put_right:Nn \l__tblr_use_hang_tl { \relax }
+        \exp_args:NV \everypar \l__tblr_use_hang_tl
+      }
+  }
+
+\tl_new:N \l__tblr_use_indent_tl
+
+\NewDocumentCommand \UseTblrIndent { m }
+  {
+    \tl_set:Nx \l__tblr_use_indent_tl { \GetTblrStyle {#1} { indent } }
+    \tl_if_empty:NF \l__tblr_use_indent_tl
+      { \exp_args:NNV \setlength \parindent \l__tblr_use_indent_tl }
+  }
+
+\AtBeginDocument
+  {
+    \@ifpackageloaded{xcolor}{}{\RenewDocumentCommand \UseTblrColor {m} {}}
+  }
+
+%% #1: head/foot element; #2: template name
+\NewExpandableDocumentCommand \ExpTblrTemplate { m m }
+  {
+    \tl_use:c { l__tblr_template_ #1 _ #2 _tl }
+  }
+
+%% #1: head/foot element; #2: template name
+\NewDocumentCommand \UseTblrTemplate { m m }
+  {
+    \group_begin:
+    \UseTblrFont {#1}
+    \UseTblrColor {#1}
+    \tl_use:c { l__tblr_template_ #1 _ #2 _tl }
+    \group_end:
+  }
+
+\NewDocumentCommand \MapTblrNotes { +m }
+  {
+    \__tblr_prop_map_inline:nn { note }
+      {
+        \tl_set_rescan:Nnn \InsertTblrNoteTag {} {##1}
+        \tl_set:Nn \InsertTblrNoteText {##2}
+        #1
+      }
+  }
+
+\NewDocumentCommand \MapTblrRemarks { +m }
+  {
+    \__tblr_prop_map_inline:nn { remark }
+      {
+        \tl_set_rescan:Nnn \InsertTblrRemarkTag {} {##1}
+        \tl_set:Nn \InsertTblrRemarkText {##2}
+        #1
+      }
+  }
+
+\NewExpandableDocumentCommand \InsertTblrText { m }
+  {
+    \__tblr_spec_item:nn { outer } {#1}
+  }
+
+\NewExpandableDocumentCommand \InsertTblrMore { m }
+  {
+    \__tblr_prop_item:nn { more } {#1}
+  }
+
+%%% --------------------------------------------------------
+%%> \section{Table Continuation Templates}
+%%% --------------------------------------------------------
+
+\DefTblrTemplate { contfoot-text } { normal } { Continued ~ on ~ next ~ page }
+\SetTblrTemplate { contfoot-text } { normal }
+
+\DefTblrTemplate { contfoot } { empty } { }
+\DefTblrTemplate { contfoot } { plain }
+  {
+    \noindent
+    \raggedleft
+    \UseTblrTemplate { contfoot-text } { default }
+    \par
+  }
+\DefTblrTemplate { contfoot } { normal }
+  {
+    %% need to set parindent after alignment
+    \raggedleft
+    \UseTblrAlign { contfoot }
+    \UseTblrIndent { contfoot }
+    \UseTblrHang { contfoot }
+    \leavevmode
+    \UseTblrTemplate { contfoot-text } { default }
+    \par
+  }
+\SetTblrTemplate { contfoot } { normal }
+
+\DefTblrTemplate { conthead-text } { normal } { ( Continued ) }
+\SetTblrTemplate { conthead-text } { normal }
+
+\DefTblrTemplate { conthead } { empty } { }
+\DefTblrTemplate { conthead } { plain }
+  {
+    \noindent
+    \raggedright
+    \UseTblrTemplate { conthead-text } { default }
+    \par
+  }
+\DefTblrTemplate { conthead } { normal }
+  {
+    %% need to set parindent after alignment
+    \raggedright
+    \UseTblrAlign { conthead }
+    \UseTblrIndent { conthead }
+    \UseTblrHang { conthead }
+    \leavevmode
+    \UseTblrTemplate { conthead-text } { default }
+    \par
+  }
+\SetTblrTemplate { conthead } { normal }
+
+%%% --------------------------------------------------------
+%%> \section{Table Caption Templates}
+%%% --------------------------------------------------------
+
+\tl_new:N \l__tblr_caption_short_tl
+
+\DefTblrTemplate { caption-lot } { empty } { }
+\DefTblrTemplate { caption-lot } { normal }
+  {
+    \tl_set:Nx \l__tblr_caption_short_tl { \InsertTblrText { entry } }
+    \tl_if_empty:NT \l__tblr_caption_short_tl
+      { \tl_set:Nx \l__tblr_caption_short_tl { \InsertTblrText { caption } } }
+    \addcontentsline { lot } { table }
+      { \protect\numberline { \thetable } { \l__tblr_caption_short_tl } }
+  }
+\SetTblrTemplate { caption-lot } { normal }
+
+%% We need to use \hspace and \enskip, but not ~ or \space,
+%% since we want a correct hangindent caption paragraph.
+
+\DefTblrTemplate { caption-tag } { empty } { }
+\DefTblrTemplate { caption-tag } { normal } { \tablename\hspace{0.25em}\thetable }
+\SetTblrTemplate { caption-tag } { normal }
+
+\DefTblrTemplate { caption-sep } { empty } { }
+\DefTblrTemplate { caption-sep } { normal } { : \enskip }
+\SetTblrTemplate { caption-sep } { normal }
+
+\DefTblrTemplate { caption-text } { empty } { }
+\DefTblrTemplate { caption-text } { normal } { \InsertTblrText { caption } }
+\SetTblrTemplate { caption-text } { normal }
+
+\box_new:N \l__tblr_caption_box
+\box_new:N \l__tblr_caption_left_box
+
+\DefTblrTemplate { caption } { empty } { }
+\DefTblrTemplate { caption } { plain }
+  {
+    \hbox_set:Nn \l__tblr_caption_box
+      {
+        \UseTblrTemplate { caption-tag } { default }
+        \UseTblrTemplate { caption-sep } { default }
+        \UseTblrTemplate { caption-text } { default }
+      }
+    \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
+      {
+        \noindent
+        \hbox_unpack:N \l__tblr_caption_box
+        \par
+      }
+      {
+        \centering
+        \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
+        \par
+      }
+  }
+\DefTblrTemplate { caption } { normal }
+  {
+    \hbox_set:Nn \l__tblr_caption_box
+      {
+        \UseTblrTemplate { caption-tag } { default }
+        \UseTblrTemplate { caption-sep } { default }
+        \UseTblrTemplate { caption-text } { default }
+      }
+    \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
+      {
+        \UseTblrAlign { caption }
+        \UseTblrIndent { caption }
+        \hbox_set:Nn \l__tblr_caption_left_box
+          {
+            \UseTblrTemplate { caption-tag } { default }
+            \UseTblrTemplate { caption-sep } { default }
+          }
+        \hangindent = \box_wd:N \l__tblr_caption_left_box
+        \hangafter = 1
+        \UseTblrHang { caption }
+        \leavevmode
+        \hbox_unpack:N \l__tblr_caption_box
+        \par
+      }
+      {
+        \centering
+        \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
+        \par
+      }
+  }
+\DefTblrTemplate { caption } { simple }
+  {
+    \UseTblrAlign { caption }
+    \UseTblrIndent { caption }
+    \UseTblrHang { caption }
+    \leavevmode
+    \UseTblrTemplate { caption-tag } { default }
+    \UseTblrTemplate { caption-sep } { default }
+    \UseTblrTemplate { caption-text } { default }
+    \par
+  }
+\SetTblrTemplate { caption } { normal }
+
+\DefTblrTemplate { capcont } { empty } { }
+\DefTblrTemplate { capcont } { plain }
+  {
+    \hbox_set:Nn \l__tblr_caption_box
+      {
+        \UseTblrTemplate { caption-tag } { default }
+        \UseTblrTemplate { caption-sep } { default }
+        \UseTblrTemplate { caption-text } { default }
+        \space
+        \UseTblrTemplate { conthead-text } { default }
+      }
+    \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
+      {
+        \noindent
+        \hbox_unpack:N \l__tblr_caption_box
+        \par
+      }
+      {
+        \centering
+        \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
+        \par
+      }
+  }
+\DefTblrTemplate { capcont } { normal }
+  {
+    \hbox_set:Nn \l__tblr_caption_box
+      {
+        \UseTblrTemplate { caption-tag } { default }
+        \UseTblrTemplate { caption-sep } { default }
+        \UseTblrTemplate { caption-text } { default }
+        \space
+        \UseTblrTemplate { conthead-text } { default }
+      }
+    \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
+      {
+        \UseTblrAlign { capcont }
+        \UseTblrIndent { capcont }
+        \hbox_set:Nn \l__tblr_caption_left_box
+          {
+            \UseTblrTemplate { caption-tag } { default }
+            \UseTblrTemplate { caption-sep } { default }
+          }
+        \hangindent = \box_wd:N \l__tblr_caption_left_box
+        \hangafter = 1
+        \UseTblrHang { capcont }
+        \leavevmode
+        \hbox_unpack:N \l__tblr_caption_box
+        \par
+      }
+      {
+        \centering
+        \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
+        \par
+      }
+  }
+\DefTblrTemplate { capcont } { simple }
+  {
+    \UseTblrAlign { caption }
+    \UseTblrIndent { caption }
+    \UseTblrHang { caption }
+    \leavevmode
+    \UseTblrTemplate { caption-tag } { default }
+    \UseTblrTemplate { caption-sep } { default }
+    \UseTblrTemplate { caption-text } { default }
+    \space
+    \UseTblrTemplate { conthead-text } { default }
+    \par
+  }
+\SetTblrTemplate { capcont} { normal }
+
+%%% --------------------------------------------------------
+%%> \section{Table Notes Templates}
+%%% --------------------------------------------------------
+
+%% By default the targets generated by \hypertarget are too low
+%% Therefore we need to use \Hy at raisedlink command to fix this problem
+%% See https://tex.stackexchange.com/questions/17057
+%% We also use \use:c in case the private command \Hy at raisedlink is removed
+\cs_new_protected:Npn \__tblr_hyper_target:n #1
+  {
+    \cs_if_exist:NT \hypertarget
+      {
+        \use:c { Hy at raisedlink }
+          {
+            \hypertarget
+              { tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} }
+              { }
+          }
+      }
+  }
+\cs_generate_variant:Nn \__tblr_hyper_target:n { V }
+
+\cs_new_protected:Npn \__tblr_hyper_link:nn #1 #2
+  {
+    \cs_if_exist:NTF \hyperlink
+      {
+        \hyperlink
+          { tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} }
+          { #2 }
+      }
+      { #2 }
+  }
+
+\DefTblrTemplate { note-border } { empty }
+  {
+    \hypersetup { pdfborder = { 0 ~ 0 ~ 0 } }
+  }
+\DefTblrTemplate { note-border } { normal }
+  {
+    \hypersetup { pdfborder = { 0 ~ 0 ~ 1 } }
+  }
+\SetTblrTemplate { note-border } { empty }
+
+\NewDocumentCommand \TblrNote { m }
+  {
+    \cs_if_exist:NT \hypersetup { \ExpTblrTemplate { note-border }{ default } }
+    \__tblr_hyper_link:nn {#1}
+      { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } }
+  }
+
+\DefTblrTemplate { note-tag } { empty } { }
+\DefTblrTemplate { note-tag } { normal }
+  {
+    \textsuperscript { \sffamily \UseTblrFont { note-tag } \InsertTblrNoteTag }
+  }
+\SetTblrTemplate { note-tag } { normal }
+
+\DefTblrTemplate { note-target } { normal }
+  {
+    \__tblr_hyper_target:V \InsertTblrNoteTag
+  }
+\SetTblrTemplate { note-target } { normal }
+
+\DefTblrTemplate { note-sep } { empty } { }
+\DefTblrTemplate { note-sep } { normal } { \space }
+\SetTblrTemplate { note-sep } { normal }
+
+\DefTblrTemplate { note-text } { empty } { }
+\DefTblrTemplate { note-text } { normal } { \InsertTblrNoteText }
+\SetTblrTemplate { note-text } { normal }
+
+\DefTblrTemplate { note } { empty } { }
+\DefTblrTemplate { note } { plain }
+  {
+    \MapTblrNotes
+      {
+        \noindent
+        \UseTblrTemplate { note-tag } { default }
+        \UseTblrTemplate { note-target } { default }
+        \UseTblrTemplate { note-sep } { default }
+        \UseTblrTemplate { note-text } { default }
+        \par
+      }
+  }
+\DefTblrTemplate { note } { normal }
+  {
+    \UseTblrAlign { note }
+    \UseTblrIndent { note }
+    \MapTblrNotes
+      {
+        \hangindent = 0.7em
+        \hangafter = 1
+        \UseTblrHang { note }
+        \leavevmode
+        \hbox_to_wd:nn { \the\hangindent }
+          {
+            \UseTblrTemplate { note-tag } { default }
+            \UseTblrTemplate { note-target } { default }
+            \hfil
+          }
+        \UseTblrTemplate { note-text } { default }
+        \par
+      }
+  }
+\DefTblrTemplate { note } { inline }
+  {
+    \UseTblrAlign { note }
+    \UseTblrIndent { note }
+    \UseTblrHang { note }
+    \leavevmode
+    \MapTblrNotes
+      {
+        \UseTblrTemplate { note-tag } { default }
+        \UseTblrTemplate { note-target } { default }
+        \UseTblrTemplate { note-sep } { default }
+        \UseTblrTemplate { note-text } { default }
+        \quad
+      }
+    \par
+  }
+\SetTblrTemplate { note } { normal }
+
+%%% --------------------------------------------------------
+%%> \section{Table Remarks Templates}
+%%% --------------------------------------------------------
+
+\DefTblrTemplate { remark-tag } { empty } { }
+\DefTblrTemplate { remark-tag } { normal }
+  {
+    \itshape \UseTblrFont { remark-tag } \InsertTblrRemarkTag
+  }
+\SetTblrTemplate { remark-tag } { normal }
+
+\DefTblrTemplate { remark-sep } { empty } { }
+\DefTblrTemplate { remark-sep } { normal } { : \space }
+\SetTblrTemplate { remark-sep } { normal }
+
+\DefTblrTemplate { remark-text } { empty } { }
+\DefTblrTemplate { remark-text } { normal } { \InsertTblrRemarkText }
+\SetTblrTemplate { remark-text } { normal }
+
+\DefTblrTemplate { remark } { empty } { }
+\DefTblrTemplate { remark } { plain }
+  {
+    \MapTblrRemarks
+      {
+        \noindent
+        \UseTblrTemplate { remark-tag } { default }
+        \UseTblrTemplate { remark-sep } { default }
+        \UseTblrTemplate { remark-text } { default }
+        \par
+      }
+  }
+\DefTblrTemplate { remark } { normal }
+  {
+    \UseTblrAlign { remark }
+    \UseTblrIndent { remark }
+    \MapTblrRemarks
+      {
+        \hangindent = 0.7em
+        \hangafter = 1
+        \UseTblrHang { remark }
+        \leavevmode
+        \UseTblrTemplate { remark-tag } { default }
+        \UseTblrTemplate { remark-sep } { default }
+        \UseTblrTemplate { remark-text } { default }
+        \par
+      }
+  }
+\DefTblrTemplate { remark } { inline }
+  {
+    \UseTblrAlign { remark }
+    \UseTblrIndent { remark }
+    \UseTblrHang { remark }
+    \leavevmode
+    \MapTblrRemarks
+      {
+        \UseTblrTemplate { remark-tag } { default }
+        \UseTblrTemplate { remark-sep } { default }
+        \UseTblrTemplate { remark-text } { default }
+        \quad
+      }
+    \par
+  }
+\SetTblrTemplate { remark } { normal }
+
+%%% --------------------------------------------------------
+%%> \section{Header and Footer Templates}
+%%% --------------------------------------------------------
+
+\tl_new:N \g__tblr_template_firsthead_default_tl
+\tl_new:N \g__tblr_template_middlehead_default_tl
+\tl_new:N \g__tblr_template_lasthead_default_tl
+\tl_new:N \g__tblr_template_firstfoot_default_tl
+\tl_new:N \g__tblr_template_middlefoot_default_tl
+\tl_new:N \g__tblr_template_lastfoot_default_tl
+
+\keys_define:nn { tblr-def-template }
+  {
+    head .meta:n = { firsthead, middlehead, lasthead },
+    foot .meta:n = { firstfoot, middlefoot, lastfoot },
+  }
+
+\keys_define:nn { tblr-set-template }
+  {
+    head .meta:n = { firsthead, middlehead, lasthead },
+    foot .meta:n = { firstfoot, middlefoot, lastfoot },
+  }
+
+\DefTblrTemplate { head } { empty } { }
+\DefTblrTemplate { foot } { empty } { }
+
+\DefTblrTemplate { firsthead } { normal }
+  {
+    \UseTblrTemplate { caption } { default }
+  }
+
+\DefTblrTemplate { middlehead, lasthead } { normal }
+  {
+    \UseTblrTemplate { capcont } { default }
+  }
+
+\DefTblrTemplate { firstfoot, middlefoot } { normal }
+  {
+    \UseTblrTemplate { contfoot } { default }
+  }
+
+\DefTblrTemplate { lastfoot } { normal }
+  {
+    \UseTblrTemplate { note } { default }
+    \UseTblrTemplate { remark } { default }
+  }
+
+\SetTblrTemplate { head } { normal }
+\SetTblrTemplate { foot } { normal }
+
+%%% --------------------------------------------------------
+%%> \section{Build the Whole Table}
+%%% --------------------------------------------------------
+
+\cs_new:Npn \__tblr_box_height:N #1
+  {
+    \dim_eval:n { \box_ht:N #1 + \box_dp:N #1 }
+  }
+
+\cs_new_protected:Npn \__tblr_build_head_foot:
+  {
+    \__tblr_build_row_head_foot:
+    \__tblr_build_table_head_foot:
+  }
+
+\tl_new:N \l__tblr_row_head_tl
+\tl_new:N \l__tblr_row_foot_tl
+\box_new:N \l__tblr_row_head_box
+\box_new:N \l__tblr_row_foot_box
+\dim_new:N \l__tblr_row_head_foot_dim
+
+\cs_new_protected:Npn \__tblr_build_row_head_foot:
+  {
+    %% \l__tblr_row_head_tl and \l__tblr_row_foot_tl may be empty
+    \tl_set:Nx \l__tblr_row_head_tl { \__tblr_prop_item:ne { inner } { rowhead } }
+    \int_compare:nNnTF { \l__tblr_row_head_tl + 0 } > { 0 }
+      { \__tblr_build_one_table:nn {1} { \l__tblr_row_head_tl } }
+      { \__tblr_build_one_hline:n {1} }
+    \box_set_eq:NN \l__tblr_row_head_box \l__tblr_table_box
+    \tl_set:Nx \l__tblr_row_foot_tl { \__tblr_prop_item:ne { inner } { rowfoot } }
+    \int_compare:nNnTF { \l__tblr_row_foot_tl + 0 } > { 0 }
+      {
+        \__tblr_build_one_table:nn
+          { \c at rowcount - \l__tblr_row_foot_tl + 1 } { \c at rowcount }
+      }
+      { \__tblr_build_one_hline:n { \int_eval:n { \c at rowcount + 1 } } }
+    \box_set_eq:NN \l__tblr_row_foot_box \l__tblr_table_box
+    \dim_set:Nn \l__tblr_row_head_foot_dim
+      {
+        \__tblr_box_height:N \l__tblr_row_head_box
+          + \__tblr_box_height:N \l__tblr_row_foot_box
+      }
+  }
+
+\dim_new:N \tablewidth
+
+\cs_new_protected:Npn \__tblr_get_table_width:
+  {
+    \dim_zero:N \tablewidth
+    \int_step_inline:nn { \c at colcount }
+      {
+        \dim_add:Nn \tablewidth
+          {
+            \__tblr_spec_item:nn { vline } { [##1] / @vline-width }
             +
-            \__tblr_data_item:nen { row } { \l__tblr_i_tl } { abovesep }
+            \__tblr_data_item:nnn { column } {##1} { leftsep }
             +
-            \__tblr_data_item:nen { row } { \l__tblr_i_tl } { @row-height }
+            \__tblr_data_item:nnn { column } {##1} { @col-width }
             +
-            \__tblr_data_item:nen { row } { \l__tblr_i_tl } { belowsep }
+            \__tblr_data_item:nnn { column } {##1} { rightsep }
           }
-        \dim_compare:nNnTF
-          { \l_tmpa_dim } > { \l__tblr_remain_height_dim }
+      }
+    \dim_add:Nn \tablewidth
+      {
+        \__tblr_spec_item:ne { vline }
+          { [\int_eval:n { \c at colcount + 1 }] / @vline-width }
+      }
+  }
+
+\box_new:N \l__tblr_table_firsthead_box
+\box_new:N \l__tblr_table_middlehead_box
+\box_new:N \l__tblr_table_lasthead_box
+\box_new:N \l__tblr_table_firstfoot_box
+\box_new:N \l__tblr_table_middlefoot_box
+\box_new:N \l__tblr_table_lastfoot_box
+
+\cs_new_protected:Npn \__tblr_build_table_head_foot:
+  {
+    \__tblr_get_table_width:
+    \__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box
+      {
+        \__tblr_build_table_label_entry:
+        \UseTblrTemplate { firsthead } { default }
+      }
+    \__tblr_build_table_head_aux:Nn
+      \l__tblr_table_middlehead_box { \UseTblrTemplate { middlehead } { default } }
+    \__tblr_build_table_head_aux:Nn
+      \l__tblr_table_lasthead_box  { \UseTblrTemplate { lasthead } { default } }
+    \__tblr_build_table_foot_aux:Nn
+      \l__tblr_table_firstfoot_box { \UseTblrTemplate { firstfoot } { default } }
+    \__tblr_build_table_foot_aux:Nn
+      \l__tblr_table_middlefoot_box { \UseTblrTemplate { middlefoot } { default } }
+    \__tblr_build_table_foot_aux:Nn
+      \l__tblr_table_lastfoot_box  { \UseTblrTemplate { lastfoot } { default } }
+  }
+
+\cs_new_protected:Npn \__tblr_build_tall_table_head_foot:
+  {
+    \__tblr_get_table_width:
+    \__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box
+      {
+        \__tblr_build_table_label_entry:
+        \UseTblrTemplate { firsthead } { default }
+      }
+    \__tblr_build_table_foot_aux:Nn
+      \l__tblr_table_lastfoot_box  { \UseTblrTemplate { lastfoot } { default } }
+  }
+
+\cs_new_protected:Npn \__tblr_build_table_label_entry:
+  {
+    \tl_set:Nx \l_tmpa_tl { \InsertTblrText { label } }
+    \tl_if_eq:NnTF \l_tmpa_tl { none }
+      {
+        \SetTblrTemplate { caption-tag }{ empty }
+        \SetTblrTemplate { caption-sep }{ empty }
+      }
+      {
+        \refstepcounter { table }
+        \tl_if_empty:NF \l_tmpa_tl { \exp_args:NV \label \l_tmpa_tl }
+      }
+    \tl_set:Nx \l_tmpb_tl { \InsertTblrText { entry } }
+    \tl_if_eq:NnF \l_tmpb_tl { none }
+      { \UseTblrTemplate { caption-lot } { default } }
+  }
+
+\cs_new_protected:Npn \__tblr_build_table_head_aux:Nn #1 #2
+  {
+    \vbox_set:Nn #1
+      {
+        \hsize = \tablewidth
+        \parindent = 0pt \relax
+        \vbox:n {#2}
+        \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } }
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_build_table_foot_aux:Nn #1 #2
+  {
+    \vbox_set:Nn #1
+      {
+        \hsize = \tablewidth
+        \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } }
+        \parindent = 0pt \relax
+        \vbox:n {#2}
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_build_whole:
+  {
+    \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { long } } { true }
+      { \__tblr_build_long_table:e { \__tblr_spec_item:nn { outer } { halign } } }
+      {
+        \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { tall } } { true }
           {
-            \tl_log:N \l__tblr_i_tl
-            \__tblr_build_page_table:nnx {#1}
-              { \l__tblr_long_from_tl } { \int_eval:n { \l__tblr_i_tl - 1 } }
+            \__tblr_build_tall_table:e
+              { \__tblr_spec_item:nn { outer } { valign } }
+          }
+          {
+            \__tblr_build_short_table:e
+              { \__tblr_spec_item:nn { outer } { valign } }
+          }
+      }
+  }
+
+\dim_new:N \l__tblr_remain_height_dim
+\int_new:N \l__tblr_long_from_int
+\int_new:N \l__tblr_long_to_int
+\int_new:N \l__tblr_curr_i_int
+\int_new:N \l__tblr_prev_i_int
+\int_new:N \l__tblr_table_page_int
+\bool_new:N \l__tblr_page_break_curr_bool
+\bool_new:N \l__tblr_page_break_prev_bool
+
+%% #1: table alignment
+%% For long table, we need to leave hmode first to get correct \pagetotal
+%% Also remove topskip and presep if we are at the beginning of the page
+\cs_new_protected:Npn \__tblr_build_long_table:n #1
+  {
+    \LogTblrTracing { page }
+    \par
+    \LogTblrTracing { page }
+    \dim_compare:nNnTF { \pagegoal } = { \maxdimen }
+      { \hbox{}\kern-\topskip\nobreak }
+      { \skip_vertical:n { \__tblr_spec_item:nn { outer } { presep } } }
+    \LogTblrTracing { page }
+    \nointerlineskip
+    \mode_leave_vertical: % enter horizontal mode to update \pagetotal
+    \LogTblrTracing { page }
+    \hrule height ~ 0pt
+    \nobreak % prevent page break after \hrule (see issue #42)
+    \LogTblrTracing { page }
+    \int_set:Nn \l__tblr_table_page_int {1}
+    \__tblr_build_head_foot:
+    \dim_set:Nn \l__tblr_remain_height_dim
+      { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim }
+    \int_set:Nn \l__tblr_long_from_int { \l__tblr_row_head_tl + 1 }
+    \int_set:Nn \l__tblr_long_to_int { \c at rowcount - ( \l__tblr_row_foot_tl + 0 ) }
+    \int_set:Nn \l__tblr_curr_i_int { \l__tblr_long_from_int - 1 }
+    \int_do_while:nNnn { \l__tblr_curr_i_int } < { \l__tblr_long_to_int }
+      {
+        \int_set_eq:NN \l__tblr_prev_i_int \l__tblr_curr_i_int
+        \__tblr_get_next_table_rows:NNNN
+          \l__tblr_long_to_int \l__tblr_curr_i_int
+          \l_tmpa_dim \l__tblr_page_break_curr_bool
+        \__tblr_check_table_page_break:NNN
+          \l__tblr_remain_height_dim \l_tmpa_dim \l__tblr_page_break_prev_bool
+        \__tblr_do_if_tracing:nn { page } { \int_log:N \l__tblr_curr_i_int }
+        \bool_if:NTF \l__tblr_page_break_prev_bool
+          {
+            \int_compare:nNnTF
+              { \l__tblr_long_from_int } > { \l__tblr_prev_i_int }
+              {
+                % See issue #42: if longtblr starts at the bottom of a page,
+                % \pagetotal maybe exceed \pagegoal after adding presep,
+                % or after adding rowhead or rowfoot of the table.
+                % In these cases, we will not typeset table in this page,
+                % but rather do some negative \vskip and execute \newpage.
+                \skip_vertical:n { \pagegoal - \pagetotal }
+              }
+              {
+                \__tblr_build_page_table:nnx {#1}
+                  { \int_use:N \l__tblr_long_from_int }
+                  { \int_use:N \l__tblr_prev_i_int }
+                \int_incr:N \l__tblr_table_page_int
+                \int_set:Nn \l__tblr_long_from_int { \l__tblr_prev_i_int + 1 }
+              }
             \newpage
             \hbox{}\kern-\topskip\nobreak
-            \leavevmode
-            %\dim_log:N \pagegoal
-            %\dim_log:N \pagetotal
+            \noindent
+            \LogTblrTracing { page }
             \dim_set:Nn \l__tblr_remain_height_dim
-              { \pagegoal - \pagetotal - \l_tmpa_dim }
-            \tl_set_eq:NN \l__tblr_long_from_tl \l__tblr_i_tl
+              { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim - \l_tmpa_dim }
           }
           {
-            \dim_add:Nn \l__tblr_remain_height_dim { -\l_tmpa_dim }
+            \bool_if:NTF \l__tblr_page_break_curr_bool
+              {
+                \__tblr_build_page_table:nnx {#1}
+                  { \int_use:N \l__tblr_long_from_int }
+                  { \int_use:N \l__tblr_curr_i_int }
+                \int_incr:N \l__tblr_table_page_int
+                \newpage
+                \hbox{}\kern-\topskip\nobreak
+                \noindent
+                \LogTblrTracing { page }
+                \dim_set:Nn \l__tblr_remain_height_dim
+                  { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim }
+                \int_set:Nn \l__tblr_long_from_int { \l__tblr_curr_i_int + 1 }
+              }
+              { \dim_add:Nn \l__tblr_remain_height_dim { -\l_tmpa_dim } }
           }
       }
-    \__tblr_build_page_table:nnn {#1} { \l__tblr_long_from_tl } { \c at rowcount }
+    \int_compare:nNnTF { \l__tblr_table_page_int } = {1}
+      {
+        \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box
+        \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box
+      }
+      {
+        \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_lasthead_box
+        \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box
+      }
+    \__tblr_build_page_table:nnn {#1}
+      { \int_use:N \l__tblr_long_from_int } { \int_use:N \l__tblr_long_to_int }
+    \skip_vertical:n { \__tblr_spec_item:nn { outer } { postsep } }
+    % In the past we used "\hrule height ~ 0pt" to get strict postsep,
+    % but the postsep was not discarded when page breaks, see issue #39.
+    % Therefore we use \nointerlineskip here.
+    \nointerlineskip
   }
+\cs_generate_variant:Nn \__tblr_build_long_table:n { e }
 
+%% #1: int with index of the last row; #2: int with index of current row;
+%% #3: row dimension; #4: break page or not.
+\cs_new_protected:Npn \__tblr_get_next_table_rows:NNNN #1 #2 #3 #4
+  {
+    \bool_set_true:N \l_tmpa_bool
+    \dim_zero:N #3
+    \bool_set_false:N #4
+    \bool_while_do:Nn \l_tmpa_bool
+      {
+        \int_incr:N #2
+        \dim_add:Nn #3
+          {
+            \__tblr_data_item:nen { row } { \int_use:N #2 } { abovesep }
+            +
+            \__tblr_data_item:nen { row } { \int_use:N #2 } { @row-height }
+            +
+            \__tblr_data_item:nen { row } { \int_use:N #2 } { belowsep }
+            +
+            \__tblr_spec_item:ne { hline }
+              { [ \int_eval:n { #2 + 1 } ] / @hline-height }
+          }
+        \int_compare:nNnTF {#2} < {#1}
+          {
+            \tl_set:Nx \l__tblr_b_tl
+              { \__tblr_data_item:nen { row } { \int_eval:n { #2 + 1 } } { break } }
+            \int_compare:nNnTF { \l__tblr_b_tl } < { 0 }
+              { \bool_set_true:N \l_tmpa_bool }
+              {
+                \bool_set_false:N \l_tmpa_bool
+                \int_compare:nNnT { \l__tblr_b_tl } > { 0 } { \bool_set_true:N #4 }
+              }
+          }
+          { \bool_set_false:N \l_tmpa_bool }
+      }
+  }
+
+\box_new:N \l__tblr_table_head_box
+\box_new:N \l__tblr_table_foot_box
+\dim_new:N \l__tblr_table_head_foot_dim
+\dim_new:N \l__tblr_table_head_body_foot_dim
+
+%% #1: remain dimension; #2: row dimension; #3: break page or not
+\cs_new_protected:Npn \__tblr_check_table_page_break:NNN #1 #2 #3
+  {
+    \int_compare:nNnTF { \l__tblr_table_page_int } = {1}
+      {
+        \dim_set:Nn \l__tblr_table_head_body_foot_dim
+          {
+            \__tblr_box_height:N \l__tblr_table_firsthead_box
+              + #2 + \__tblr_box_height:N \l__tblr_table_firstfoot_box
+          }
+        \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box
+        \dim_compare:nNnTF
+          { \l__tblr_table_head_body_foot_dim } > {#1}
+          {
+            \bool_set_true:N #3
+            \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_firstfoot_box
+          }
+          { \bool_set_false:N #3 }
+      }
+      {
+        \dim_set:Nn \l__tblr_table_head_body_foot_dim
+          {
+            \__tblr_box_height:N \l__tblr_table_middlehead_box
+              + #2 + \__tblr_box_height:N \l__tblr_table_middlefoot_box
+          }
+        \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_middlehead_box
+        \dim_compare:nNnTF
+          { \l__tblr_table_head_body_foot_dim } > {#1}
+          {
+            \bool_set_true:N #3
+            \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_middlefoot_box
+          }
+          { \bool_set_false:N #3 }
+      }
+  }
+
+\box_new:N \l__tblr_table_box
+
+%% #1: table alignment; #2: row from; #3: row to
 \cs_new_protected:Npn \__tblr_build_page_table:nnn #1 #2 #3
   {
+    \bool_set_false:N \l__tblr_build_first_hline_bool
+    \bool_set_false:N \l__tblr_build_last_hline_bool
     \__tblr_build_one_table:nn {#2} {#3}
+    \vbox_set:Nn \l__tblr_table_box
+      {
+        \box_use:N \l__tblr_table_head_box
+        \__tblr_cover_two_vboxes:NN \l__tblr_row_head_box \l__tblr_table_box
+        \box_use:N \l__tblr_row_foot_box
+        \hrule height ~ 0pt
+        \box_use:N \l__tblr_table_foot_box
+      }
     \__tblr_halign_whole:Nn \l__tblr_table_box #1
   }
 \cs_generate_variant:Nn \__tblr_build_page_table:nnn { nnx }
 
+%% To solve the problem of missing hlines of long tables in some PDF readers,
+%% We need to draw body rows before head rows (see issue #88).
+\cs_new_protected:Npn \__tblr_cover_two_vboxes:NN #1 #2
+  {
+    \dim_set:Nn \l_tmpa_dim { \box_ht:N #1 + \box_dp:N #1 }
+    \dim_set:Nn \l_tmpb_dim { \box_ht:N #2 + \box_dp:N #2 }
+    \skip_vertical:N \l_tmpa_dim
+    \hrule height ~ 0pt
+    \box_use:N #2
+    \skip_vertical:n { - \l_tmpa_dim - \l_tmpb_dim }
+    \hrule height ~ 0pt
+    \box_use:N #1
+    \skip_vertical:N \l_tmpb_dim
+    \hrule height ~ 0pt
+  }
+
 \cs_new_protected:Npn \__tblr_halign_whole:Nn #1 #2
   {
     \noindent
@@ -3818,42 +5456,129 @@
       }
   }
 
+%% #1: table alignment
+%% For tall table, we need to leave vmode first.
+%% Since there may be \centering in table environment,
+%% We use \raggedright to reset alignement for table head/foot.
+\cs_new_protected:Npn \__tblr_build_tall_table:n #1
+  {
+    \mode_leave_vertical:
+    \raggedright
+    \__tblr_build_tall_table_head_foot:
+    \__tblr_build_one_table:nn {1} {\c at rowcount}
+    \vbox_set:Nn \l__tblr_table_box
+      {
+        \box_use:N \l__tblr_table_firsthead_box
+        \hrule height ~ 0pt
+        \box_use:N \l__tblr_table_box
+        \hrule height ~ 0pt
+        \box_use:N \l__tblr_table_lastfoot_box
+      }
+    \__tblr_valign_whole:Nn \l__tblr_table_box #1
+  }
+\cs_generate_variant:Nn \__tblr_build_tall_table:n { e }
+
+%% #1: table alignment
+%% For short table, we need to leave vmode first
 \cs_new_protected:Npn \__tblr_build_short_table:n #1
   {
+    \mode_leave_vertical:
     \__tblr_build_one_table:nn {1} {\c at rowcount}
     \__tblr_valign_whole:Nn \l__tblr_table_box #1
   }
+\cs_generate_variant:Nn \__tblr_build_short_table:n { e }
 
+\bool_new:N \l__tblr_build_first_hline_bool
+\bool_new:N \l__tblr_build_last_hline_bool
+\bool_set_true:N \l__tblr_build_first_hline_bool
+\bool_set_true:N \l__tblr_build_last_hline_bool
+\box_new:N \l__tblr_table_hlines_box
+\box_new:N \l__tblr_hline_box
+\box_new:N \l__tblr_row_box
+
 %% #1: row from; #2: row to
+%% To fix disappeared hlines with colorful tables in Adobe Reader (see #76),
+%% we collect all hlines and draw them at the end of the table.
 \cs_new_protected:Npn \__tblr_build_one_table:nn #1 #2
   {
+    \box_clear:N \l__tblr_table_hlines_box
     \vbox_set:Nn \l__tblr_table_box
       {
         \int_step_variable:nnNn {#1} {#2} \l__tblr_i_tl
           {
-            \hbox:n { \__tblr_build_hline:V \l__tblr_i_tl }
+            \bool_lazy_or:nnT
+              { \int_compare_p:nNn { \l__tblr_i_tl } > {#1} }
+              { \bool_if_p:N \l__tblr_build_first_hline_bool }
+              { \__tblr_put_one_hline:n { \__tblr_build_hline:V \l__tblr_i_tl } }
             \hrule height ~ 0pt % remove lineskip between hlines and rows
-            \hbox:n { \__tblr_build_row:N \l__tblr_i_tl }
+            \__tblr_put_one_row:n { \__tblr_build_row:N \l__tblr_i_tl }
             \hrule height ~ 0pt
           }
-        \hbox:n { \__tblr_build_hline:n { \int_eval:n {#2 + 1} } }
+        \bool_if:NT \l__tblr_build_last_hline_bool
+          {
+            \__tblr_put_one_hline:n
+              { \__tblr_build_hline:n { \int_eval:n {#2 + 1} } }
+          }
+        \skip_vertical:n
+          {
+            - \box_ht:N \l__tblr_table_hlines_box
+            - \box_dp:N \l__tblr_table_hlines_box
+          }
+        \box_use:N \l__tblr_table_hlines_box
       }
+    \bool_set_true:N \l__tblr_build_first_hline_bool
+    \bool_set_true:N \l__tblr_build_last_hline_bool
   }
 
+\cs_new_protected:Npn \__tblr_put_one_hline:n #1
+  {
+    \hbox_set:Nn \l__tblr_hline_box {#1}
+    \skip_vertical:n { \box_ht:N \l__tblr_hline_box + \box_dp:N \l__tblr_hline_box }
+    \vbox_set:Nn \l__tblr_table_hlines_box
+      {
+        \vbox_unpack:N \l__tblr_table_hlines_box
+        \box_use:N \l__tblr_hline_box
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_put_one_row:n #1
+  {
+    \hbox_set:Nn \l__tblr_row_box {#1}
+    \vbox_set:Nn \l__tblr_table_hlines_box
+      {
+        \vbox_unpack:N \l__tblr_table_hlines_box
+        \skip_vertical:n
+          { \box_ht:N \l__tblr_row_box + \box_dp:N \l__tblr_row_box }
+      }
+    \box_use:N \l__tblr_row_box
+  }
+
+%% #1: hline number
+\cs_new_protected:Npn \__tblr_build_one_hline:n #1
+  {
+    \vbox_set:Nn \l__tblr_table_box { \hbox:n { \__tblr_build_hline:n { #1 } } }
+  }
+
+\tl_new:N \__tblr_vbox_align_tl
+\tl_const:Nn \__tblr_vbox_t_tl {t}
+\tl_const:Nn \__tblr_vbox_m_tl {m}
+\tl_const:Nn \__tblr_vbox_c_tl {c}
+\tl_const:Nn \__tblr_vbox_b_tl {b}
+
 \cs_new_protected:Npn \__tblr_valign_whole:Nn #1 #2
   {
     \group_begin:
-    \tl_set:Nn \__tlbr_vbox_align_tl {#2}
+    \tl_set:Nn \__tblr_vbox_align_tl {#2}
     \dim_set:Nn \l__tblr_t_dim { \box_ht:N #1 + \box_dp:N #1 }
-    \tl_case:NnF \__tlbr_vbox_align_tl
+    \tl_case:NnF \__tblr_vbox_align_tl
       {
-        \__tlbr_vbox_m_tl
+        \__tblr_vbox_m_tl
           { \__tblr_valign_whole_middle:N #1 }
-        \__tlbr_vbox_c_tl
+        \__tblr_vbox_c_tl
           { \__tblr_valign_whole_middle:N #1 }
-        \__tlbr_vbox_t_tl
+        \__tblr_vbox_t_tl
           { \__tblr_valign_whole_top:N #1 }
-        \__tlbr_vbox_b_tl
+        \__tblr_vbox_b_tl
           { \__tblr_valign_whole_bottom:N #1 }
       }
       { \__tblr_valign_whole_middle:N #1 }
@@ -3868,10 +5593,10 @@
 \cs_new_protected:Npn \__tblr_valign_whole_top:N #1
   {
     \tl_set:Nx \l__tblr_a_tl
-      { \__tblr_text_item:ne { hline } { [1] / @hline-height } }
+      { \__tblr_spec_item:ne { hline } { [1] / @hline-height } }
     %% Note that \l__tblr_b_tl may be empty
     \tl_set:Nx \l__tblr_b_tl
-      { \__tblr_prop_item:ne { table } { baseline } }
+      { \__tblr_prop_item:ne { inner } { baseline } }
     \bool_lazy_or:nnTF
       { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } }
       { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { 1 } }
@@ -3902,12 +5627,12 @@
   {
     \tl_set:Nx \l__tblr_a_tl
       {
-        \__tblr_text_item:ne { hline }
+        \__tblr_spec_item:ne { hline }
           { [\int_eval:n {\c at rowcount + 1}] / @hline-height }
       }
     %% Note that \l__tblr_b_tl may be empty
     \tl_set:Nx \l__tblr_b_tl
-      { \__tblr_prop_item:ne { table } { baseline } }
+      { \__tblr_prop_item:ne { inner } { baseline } }
     \bool_lazy_or:nnTF
       { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } }
       { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { \c at rowcount } }
@@ -3937,6 +5662,10 @@
     \box_use_drop:N #1
   }
 
+%%% --------------------------------------------------------
+%%> \section{Build Table Components}
+%%% --------------------------------------------------------
+
 \dim_new:N \l__tblr_col_o_wd_dim
 \dim_new:N \l__tblr_col_b_wd_dim
 
@@ -3952,9 +5681,9 @@
 \cs_new_protected:Npn \__tblr_build_hline_segment:nn #1 #2
   {
     \tl_set:Nx \l__tblr_n_tl
-      { \__tblr_text_item:ne { hline } { [#1] / @hline-count } }
+      { \__tblr_spec_item:ne { hline } { [#1] / @hline-count } }
     \tl_set:Nx \l__tblr_o_tl
-      { \__tblr_text_item:ne { hline } { [#1][#2] / omit } }
+      { \__tblr_spec_item:ne { hline } { [#1][#2] / omit } }
     \__tblr_get_col_outer_width_border_width:nNN {#2}
       \l__tblr_col_o_wd_dim \l__tblr_col_b_wd_dim
     \tl_if_empty:NTF \l__tblr_o_tl
@@ -3975,7 +5704,7 @@
 \cs_new_protected:Npn \__tblr_build_hline_segment_real:nn #1 #2
   {
     \tl_set:Nx \l__tblr_s_tl
-      { \__tblr_prop_item:ne { table } { rulesep } }
+      { \__tblr_prop_item:ne { inner } { rulesep } }
     \vbox_set:Nn \l__tblr_c_box
       {
         %% add an empty hbox to support vbox width
@@ -3983,14 +5712,17 @@
         \int_step_inline:nn { \l__tblr_n_tl }
           {
             \tl_set:Nx \l__tblr_h_tl
-              { \__tblr_text_item:ne { hline } { [#1](##1) / @hline-height } }
+              { \__tblr_spec_item:ne { hline } { [#1](##1) / @hline-height } }
             \hrule height ~ 0pt % remove lineskip
             \hbox_set_to_wd:Nnn \l__tblr_b_box { \l__tblr_col_o_wd_dim }
               {
+                \__tblr_get_hline_left_right_skips:nnn {#1} {#2} {##1}
+                \skip_horizontal:N \l__tblr_hline_leftskip_dim
                 \tl_set:Nx \l__tblr_f_tl
-                  { \__tblr_text_item:ne { hline } { [#1][#2](##1) / fg } }
+                  { \__tblr_spec_item:ne { hline } { [#1][#2](##1) / fg } }
                 \tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} }
                 \__tblr_get_hline_segment_child:nnn {#1} {#2} {##1}
+                \skip_horizontal:N \l__tblr_hline_rightskip_dim
               }
             \box_set_ht:Nn \l__tblr_b_box { \l__tblr_h_tl }
             \box_set_dp:Nn \l__tblr_b_box { 0pt }
@@ -4009,10 +5741,10 @@
 \cs_new_protected:Npn \__tblr_get_col_outer_width_border_width:nNN #1 #2 #3
   {
     \dim_set:Nn #3
-      { \__tblr_text_item:ne { vline } { [\int_eval:n {#1 + 1}] / @vline-width } }
+      { \__tblr_spec_item:ne { vline } { [\int_eval:n {#1 + 1}] / @vline-width } }
     \dim_set:Nn #2
       {
-        \__tblr_text_item:ne { vline } { [#1] / @vline-width }
+        \__tblr_spec_item:ne { vline } { [#1] / @vline-width }
         +
         \__tblr_data_item:nen { column } {#1} { leftsep }
         +
@@ -4024,24 +5756,92 @@
       }
   }
 
+\dim_new:N \l__tblr_hline_leftskip_dim
+\dim_new:N \l__tblr_hline_rightskip_dim
+
+%% Calculate left and right skips from leftpos and rightpos specifications
+%% #1: row number; #2: column number; #3: hline index;
+\cs_new_protected:Npn \__tblr_get_hline_left_right_skips:nnn #1 #2 #3
+  {
+    \tl_set:Nx \l__tblr_hline_leftpos_tl
+      { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / leftpos } }
+    \tl_if_empty:NT \l__tblr_hline_leftpos_tl
+      { \tl_set:Nn \l__tblr_hline_leftpos_tl {1} } % default position
+    \tl_set:Nx \l__tblr_hline_rightpos_tl
+      { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / rightpos } }
+    \tl_if_empty:NT \l__tblr_hline_rightpos_tl
+      { \tl_set:Nn \l__tblr_hline_rightpos_tl {1} } % default position
+    \fp_compare:nNnT { \l__tblr_hline_leftpos_tl } < {1}
+      {
+        \dim_set:Nn \l_tmpa_dim
+          { \__tblr_spec_item:ne { vline } { [#2] / @vline-width } }
+        \dim_set:Nn \l_tmpb_dim
+          { \__tblr_data_item:nen { column } {#2} { leftsep } }
+        \fp_compare:nNnTF { \l__tblr_hline_leftpos_tl } < {0}
+          {
+            \dim_set:Nn \l__tblr_hline_leftskip_dim
+              { \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpb_dim }
+          }
+          {
+            \dim_set:Nn \l__tblr_hline_leftskip_dim
+              { \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpa_dim }
+          }
+      }
+    \fp_compare:nNnT { \l__tblr_hline_rightpos_tl } < {1}
+      {
+        \dim_set:Nn \l_tmpa_dim
+          {
+            \__tblr_spec_item:ne { vline }
+              { [\int_eval:n { #2 + 1 }] / @vline-width }
+          }
+        \dim_set:Nn \l_tmpb_dim
+          { \__tblr_data_item:nen { column } {#2} { rightsep } }
+        \fp_compare:nNnTF { \l__tblr_hline_rightpos_tl } < {0}
+          {
+            \dim_set:Nn \l__tblr_hline_rightskip_dim
+              { \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpb_dim }
+          }
+          {
+            \dim_set:Nn \l__tblr_hline_rightskip_dim
+              { \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpa_dim }
+          }
+      }
+  }
+
 \dim_new:N \l__tblr_row_ht_dim
 \dim_new:N \l__tblr_row_dp_dim
 \dim_new:N \l__tblr_row_abovesep_dim
 \dim_new:N \l__tblr_row_belowsep_dim
+\box_new:N \l__tblr_row_vlines_box
+\box_new:N \l__tblr_vline_box
+\box_new:N \l__tblr_cell_box
 
 %% Build current row, #1: row number
+%% To fix disappeared vlines with colorful tables in Adobe Reader (see #76),
+%% we collect all vlines and draw them at the end of the row.
 \cs_new_protected:Npn \__tblr_build_row:N #1
   {
+    \int_set:Nn \c at rownum {#1}
+    \__tblr_update_rowsep_registers:
     \__tblr_get_row_inner_height_depth:VNNNN #1
       \l__tblr_row_ht_dim \l__tblr_row_dp_dim
       \l__tblr_row_abovesep_dim \l__tblr_row_belowsep_dim
     \vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim ~ depth ~ \l__tblr_row_dp_dim
+    \hbox_set:Nn \l__tblr_row_vlines_box
+      {
+        \vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim
+                           ~ depth ~ \l__tblr_row_dp_dim
+      }
     \int_step_variable:nNn { \c at colcount } \l__tblr_j_tl
       {
-        \__tblr_build_vline_segment:nn {#1} { \l__tblr_j_tl }
-        \__tblr_build_cell:NN #1 \l__tblr_j_tl
+        \__tblr_put_one_vline:n
+          { \__tblr_build_vline_segment:nn {#1} { \l__tblr_j_tl } }
+        \__tblr_put_one_cell:n { \__tblr_build_cell:NN #1 \l__tblr_j_tl }
       }
-    \__tblr_build_vline_segment:nn {#1} { \int_eval:n {\c at colcount + 1} }
+    \__tblr_put_one_vline:n
+      { \__tblr_build_vline_segment:nn {#1} { \int_eval:n {\c at colcount + 1} } }
+    \skip_horizontal:n { - \box_wd:N \l__tblr_row_vlines_box }
+    \box_use:N \l__tblr_row_vlines_box
   }
 
 %% Read from table specifications and calculate inner height/depth of the row
@@ -4074,13 +5874,35 @@
   }
 \cs_generate_variant:Nn \__tblr_get_row_inner_height_depth:nNNNN { V }
 
+\cs_new_protected:Npn \__tblr_put_one_vline:n #1
+  {
+    \hbox_set:Nn \l__tblr_vline_box {#1}
+    \skip_horizontal:n { \box_wd:N \l__tblr_vline_box }
+    \hbox_set:Nn \l__tblr_row_vlines_box
+      {
+        \hbox_unpack:N \l__tblr_row_vlines_box
+        \box_use:N \l__tblr_vline_box
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_put_one_cell:n #1
+  {
+    \hbox_set:Nn \l__tblr_cell_box {#1}
+    \hbox_set:Nn \l__tblr_row_vlines_box
+      {
+        \hbox_unpack:N \l__tblr_row_vlines_box
+        \skip_horizontal:n { \box_wd:N \l__tblr_cell_box }
+      }
+    \box_use:N \l__tblr_cell_box
+  }
+
 %% #1: row number, #2: column number
 \cs_new_protected:Npn \__tblr_build_vline_segment:nn #1 #2
   {
     \tl_set:Nx \l__tblr_n_tl
-      { \__tblr_text_item:ne { vline } { [#2] / @vline-count } }
+      { \__tblr_spec_item:ne { vline } { [#2] / @vline-count } }
     \tl_set:Nx \l__tblr_o_tl
-      { \__tblr_text_item:ne { vline } { [#1][#2] / omit } }
+      { \__tblr_spec_item:ne { vline } { [#1][#2] / omit } }
     \tl_if_empty:NTF \l__tblr_o_tl
       {
         \int_compare:nNnT { \l__tblr_n_tl } > {0}
@@ -4093,7 +5915,7 @@
 \cs_new_protected:Npn \__tblr_build_vline_segment_omit:nn #1 #2
   {
     \tl_set:Nx \l__tblr_w_tl
-      { \__tblr_text_item:ne { vline } { [#2] / @vline-width } }
+      { \__tblr_spec_item:ne { vline } { [#2] / @vline-width } }
     \skip_horizontal:N \l__tblr_w_tl
   }
 
@@ -4103,29 +5925,25 @@
 \cs_new_protected:Npn \__tblr_build_vline_segment_real:nn #1 #2
   {
     \tl_set:Nx \l__tblr_s_tl
-      { \__tblr_prop_item:ne { table } { rulesep } }
-    \tl_set:Nx \l__tblr_b_tl
-      {
-        \__tblr_text_item:ne { hline }
-          { [\int_eval:n{#1 + 1}](1) / @hline-height }
-      }
-    \tl_if_empty:NT \l__tblr_b_tl { \tl_set:Nn \l__tblr_b_tl { 0pt } }
+      { \__tblr_prop_item:ne { inner } { rulesep } }
     \hbox_set:Nn \l__tblr_a_box
       {
         \int_step_inline:nn { \l__tblr_n_tl }
           {
             \tl_set:Nx \l__tblr_w_tl
-              { \__tblr_text_item:ne { vline } { [#2](##1) / @vline-width } }
+              { \__tblr_spec_item:ne { vline } { [#2](##1) / @vline-width } }
             \vbox_set_to_ht:Nnn \l__tblr_b_box
               { \dim_eval:n { \l__tblr_row_ht_dim + \l__tblr_row_dp_dim } }
               {
                 \tl_set:Nx \l__tblr_f_tl
-                  { \__tblr_text_item:ne { vline } { [#1][#2](##1) / fg } }
+                  { \__tblr_spec_item:ne { vline } { [#1][#2](##1) / fg } }
                 \tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} }
+                \__tblr_get_vline_above_below_skips:nnn {#1} {#2} {##1}
+                \skip_vertical:N \l__tblr_vline_aboveskip_dim
                 \__tblr_get_vline_segment_child:nnnxx {#1} {#2} {##1}
                   { \dim_eval:n { \l__tblr_row_ht_dim } }
-                  { \dim_eval:n { \l__tblr_row_dp_dim + \l__tblr_b_tl } }
-                \skip_vertical:n {  - \l__tblr_b_tl }
+                  { \dim_eval:n { \l__tblr_row_dp_dim } }
+                \skip_vertical:N \l__tblr_vline_belowskip_dim
               }
             \box_set_wd:Nn \l__tblr_b_box { \l__tblr_w_tl }
             \box_use:N \l__tblr_b_box
@@ -4139,6 +5957,68 @@
     \box_use:N \l__tblr_c_box
   }
 
+\dim_new:N \l__tblr_vline_aboveskip_dim
+\dim_new:N \l__tblr_vline_belowskip_dim
+
+%% Calculate above and below skips from abovepos and belowpos specifications
+%% #1: row number; #2: column number; #3: vline index;
+\cs_new_protected:Npn \__tblr_get_vline_above_below_skips:nnn #1 #2 #3
+  {
+    \tl_set:Nx \l__tblr_vline_abovepos_tl
+      { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / abovepos } }
+    \tl_if_empty:NT \l__tblr_vline_abovepos_tl
+      {
+        \tl_set:Nn \l__tblr_vline_abovepos_tl {0} % default position
+      }
+    \tl_set:Nx \l__tblr_vline_belowpos_tl
+      { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / belowpos } }
+    \tl_if_empty:NT \l__tblr_vline_belowpos_tl
+      {
+        \tl_set:Nn \l__tblr_vline_belowpos_tl {0} % default position
+      }
+    \fp_compare:nNnF { \l__tblr_vline_abovepos_tl } = {0}
+      {
+        \dim_set:Nn \l_tmpa_dim
+          { \__tblr_spec_item:ne { hline } { [#1] / @hline-height } }
+        \fp_compare:nNnTF { \l__tblr_vline_abovepos_tl } < {0}
+          {
+            \dim_set:Nn \l__tblr_vline_aboveskip_dim
+              { - \l__tblr_vline_abovepos_tl \l__tblr_row_abovesep_dim }
+          }
+          {
+            \dim_set:Nn \l__tblr_vline_aboveskip_dim
+              { - \l__tblr_vline_abovepos_tl \l_tmpa_dim }
+          }
+      }
+    %% To join two vline segment above and below a cline,
+    %% we choose to extend every vline downwards a little (#55).
+    \fp_compare:nNnTF { \l__tblr_vline_belowpos_tl } = {0}
+      {
+        \dim_set:Nn \l__tblr_vline_belowskip_dim
+          {
+            - \__tblr_spec_item:ne { hline }
+                { [\int_eval:n { #1 + 1 }](1) / @hline-height }
+            + 0pt
+          }
+      }
+      {
+        \dim_set:Nn \l_tmpa_dim
+          {
+            \__tblr_spec_item:ne { hline }
+              { [\int_eval:n { #1 + 1 }] / @hline-height }
+          }
+        \fp_compare:nNnTF { \l__tblr_vline_belowpos_tl } < {0}
+          {
+            \dim_set:Nn \l__tblr_vline_belowskip_dim
+              { - \l__tblr_vline_belowpos_tl \l__tblr_row_belowsep_dim }
+          }
+          {
+            \dim_set:Nn \l__tblr_vline_belowskip_dim
+              { - \l__tblr_vline_belowpos_tl \l_tmpa_dim }
+          }
+      }
+  }
+
 \tl_new:N \l__tblr_cell_rowspan_tl
 \tl_new:N \l__tblr_cell_colspan_tl
 \dim_new:N \l__tblr_cell_wd_dim
@@ -4146,8 +6026,8 @@
 
 \cs_new_protected:Npn \__tblr_build_cell:NN #1 #2
   {
-    \int_set:Nn \c at rownum {#1}
     \int_set:Nn \c at colnum {#2}
+    \__tblr_update_colsep_registers:
     \group_begin:
     \tl_set:Nx \l__tblr_w_tl
       { \__tblr_data_item:nen { column } {#2} { @col-width } }
@@ -4183,9 +6063,13 @@
   {
     \hbox_set_to_wd:Nnn \l__tblr_a_box { \l__tblr_cell_wd_dim }
       {
-        \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil }
-        \__tblr_get_cell_text:nn {#1} {#2}
-        \tl_if_eq:NnF \g__tblr_cell_halign_tl {r} { \hfil }
+        \tl_if_eq:NnTF \g__tblr_cell_halign_tl {j}
+          { \__tblr_get_cell_text:nn {#1} {#2} }
+          {
+            \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil }
+            \__tblr_get_cell_text:nn {#1} {#2}
+            \tl_if_eq:NnF \g__tblr_cell_halign_tl {r} { \hfil }
+          }
       }
     \vbox_set_to_ht:Nnn \l__tblr_b_box { \l__tblr_cell_ht_dim }
       {
@@ -4305,21 +6189,24 @@
 %% #1: row number; #2: column number; #3: dimen register for rowsep above.
 %% #4: dimen register for total height; #5: dimen register for rowsep below.
 %% We can use \l__tblr_row_item_skip_size_prop which was made before
+%% But when vspan=even, there are no itemskip in the prop list.
+%% Therefore we need to calculate them from the sizes of items and skips
 \cs_new_protected:Npn \__tblr_get_span_vertical_sizes:NNNNN #1 #2 #3 #4 #5
   {
     \dim_set:Nn #3
       { \__tblr_data_item:nen { row } {#1} { abovesep } }
     \dim_zero:N #4
-    \int_step_inline:nnn { #1 } { #1 + \l__tblr_cell_rowspan_tl - 2 }
+    \dim_add:Nn #4
+      { \prop_item:Ne \l__tblr_row_item_skip_size_prop { item[#1] } }
+    \int_step_inline:nnn { #1 + 1 } { #1 + \l__tblr_cell_rowspan_tl - 1 }
       {
         \dim_add:Nn #4
-          { \prop_item:Ne \l__tblr_row_item_skip_size_prop { itemskip[##1] } }
+          {
+            \prop_item:Ne \l__tblr_row_item_skip_size_prop { skip[##1] }
+            +
+            \prop_item:Ne \l__tblr_row_item_skip_size_prop { item[##1] }
+          }
       }
-    \dim_add:Nn #4
-      {
-        \prop_item:Ne \l__tblr_row_item_skip_size_prop
-          { item[\int_eval:n { #1 + \l__tblr_cell_rowspan_tl - 1 }] }
-      }
     \dim_set:Nn #5
       {
         \__tblr_data_item:nen { row }
@@ -4331,7 +6218,7 @@
 %% #1: row number; #2: column number; #3: dimen register for colsep left.
 %% #4: dimen register for total width; #5: dimen register for colsep right.
 %% We can use \l__tblr_col_item_skip_size_prop which was made before
-%% But when hspan=minimal, there are no itemskip in the prop list.
+%% But when hspan=even or hspan=minimal, there are no itemskip in the prop list.
 %% Therefore we need to calculate them from the sizes of items and skips
 \cs_new_protected:Npn \__tblr_get_span_horizontal_sizes:NNNNN #1 #2 #3 #4 #5
   {
@@ -4338,21 +6225,17 @@
     \dim_set:Nn #3
       { \__tblr_data_item:nen { column } {#2} { leftsep } }
     \dim_zero:N #4
-    \int_step_inline:nnn { #2 } { #2 + \l__tblr_cell_colspan_tl - 2 }
+    \dim_add:Nn #4
+      { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#2] } }
+    \int_step_inline:nnn { #2 + 1 } { #2 + \l__tblr_cell_colspan_tl - 1 }
       {
         \dim_add:Nn #4
-          { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } }
-        \dim_add:Nn #4
           {
-            \prop_item:Ne \l__tblr_col_item_skip_size_prop
-              { skip[\int_eval:n { ##1 + 1 }] }
+            \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] }
+            +
+            \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] }
           }
       }
-    \dim_add:Nn #4
-      {
-        \prop_item:Ne \l__tblr_col_item_skip_size_prop
-          { item[\int_eval:n { #2 + \l__tblr_cell_colspan_tl - 1 }] }
-      }
     \dim_set:Nn #5
       {
         \__tblr_data_item:nen { column }
@@ -4373,7 +6256,10 @@
 
 \bool_new:N \g__tblr_tracing_text_bool
 \bool_new:N \g__tblr_tracing_command_bool
-\bool_new:N \g__tblr_tracing_table_bool
+\bool_new:N \g__tblr_tracing_option_bool
+\bool_new:N \g__tblr_tracing_theme_bool
+\bool_new:N \g__tblr_tracing_outer_bool
+\bool_new:N \g__tblr_tracing_inner_bool
 \bool_new:N \g__tblr_tracing_column_bool
 \bool_new:N \g__tblr_tracing_row_bool
 \bool_new:N \g__tblr_tracing_cell_bool
@@ -4384,7 +6270,11 @@
 \bool_new:N \g__tblr_tracing_target_bool
 \bool_new:N \g__tblr_tracing_cellspan_bool
 \bool_new:N \g__tblr_tracing_intarray_bool
+\bool_new:N \g__tblr_tracing_page_bool
+\bool_new:N \g__tblr_tracing_step_bool
 
+\bool_gset_true:N \g__tblr_tracing_step_bool
+
 \keys_define:nn { tblr-set-tracing }
   {
     +text .code:n = \bool_gset_true:N \g__tblr_tracing_text_bool,
@@ -4391,8 +6281,14 @@
     -text .code:n = \bool_gset_false:N \g__tblr_tracing_text_bool,
     +command .code:n = \bool_gset_true:N \g__tblr_tracing_command_bool,
     -command .code:n = \bool_gset_false:N \g__tblr_tracing_command_bool,
-    +table .code:n = \bool_gset_true:N \g__tblr_tracing_table_bool,
-    -table .code:n = \bool_gset_false:N \g__tblr_tracing_table_bool,
+    +option .code:n = \bool_gset_true:N \g__tblr_tracing_option_bool,
+    -option .code:n = \bool_gset_false:N \g__tblr_tracing_option_bool,
+    +theme .code:n = \bool_gset_true:N \g__tblr_tracing_theme_bool,
+    -theme .code:n = \bool_gset_false:N \g__tblr_tracing_theme_bool,
+    +outer .code:n = \bool_gset_true:N \g__tblr_tracing_outer_bool,
+    -outer .code:n = \bool_gset_false:N \g__tblr_tracing_outer_bool,
+    +inner .code:n = \bool_gset_true:N \g__tblr_tracing_inner_bool,
+    -inner .code:n = \bool_gset_false:N \g__tblr_tracing_inner_bool,
     +column .code:n = \bool_gset_true:N \g__tblr_tracing_column_bool,
     -column .code:n = \bool_gset_false:N \g__tblr_tracing_column_bool,
     +row .code:n = \bool_gset_true:N \g__tblr_tracing_row_bool,
@@ -4413,6 +6309,10 @@
     -cellspan .code:n = \bool_gset_false:N \g__tblr_tracing_cellspan_bool,
     +intarray .code:n = \bool_gset_true:N \g__tblr_tracing_intarray_bool,
     -intarray .code:n = \bool_gset_false:N \g__tblr_tracing_intarray_bool,
+    +page .code:n = \bool_gset_true:N \g__tblr_tracing_page_bool,
+    -page .code:n = \bool_gset_false:N \g__tblr_tracing_page_bool,
+    +step .code:n = \bool_gset_true:N \g__tblr_tracing_step_bool,
+    -step .code:n = \bool_gset_false:N \g__tblr_tracing_step_bool,
     all .code:n = \__tblr_enable_all_tracings:,
     none .code:n = \__tblr_disable_all_tracings:,
   }
@@ -4421,7 +6321,10 @@
   {
     \bool_gset_true:N \g__tblr_tracing_text_bool
     \bool_gset_true:N \g__tblr_tracing_command_bool
-    \bool_gset_true:N \g__tblr_tracing_table_bool
+    \bool_gset_true:N \g__tblr_tracing_option_bool
+    \bool_gset_true:N \g__tblr_tracing_theme_bool
+    \bool_gset_true:N \g__tblr_tracing_outer_bool
+    \bool_gset_true:N \g__tblr_tracing_inner_bool
     \bool_gset_true:N \g__tblr_tracing_column_bool
     \bool_gset_true:N \g__tblr_tracing_row_bool
     \bool_gset_true:N \g__tblr_tracing_cell_bool
@@ -4432,6 +6335,8 @@
     \bool_gset_true:N \g__tblr_tracing_target_bool
     \bool_gset_true:N \g__tblr_tracing_cellspan_bool
     \bool_gset_true:N \g__tblr_tracing_intarray_bool
+    \bool_gset_true:N \g__tblr_tracing_page_bool
+    \bool_gset_true:N \g__tblr_tracing_step_bool
   }
 
 \cs_new_protected_nopar:Npn \__tblr_disable_all_tracings:
@@ -4438,7 +6343,10 @@
   {
     \bool_gset_false:N \g__tblr_tracing_text_bool
     \bool_gset_false:N \g__tblr_tracing_command_bool
-    \bool_gset_false:N \g__tblr_tracing_table_bool
+    \bool_gset_false:N \g__tblr_tracing_option_bool
+    \bool_gset_false:N \g__tblr_tracing_theme_bool
+    \bool_gset_false:N \g__tblr_tracing_outer_bool
+    \bool_gset_false:N \g__tblr_tracing_inner_bool
     \bool_gset_false:N \g__tblr_tracing_column_bool
     \bool_gset_false:N \g__tblr_tracing_row_bool
     \bool_gset_false:N \g__tblr_tracing_cell_bool
@@ -4449,6 +6357,8 @@
     \bool_gset_false:N \g__tblr_tracing_target_bool
     \bool_gset_false:N \g__tblr_tracing_cellspan_bool
     \bool_gset_false:N \g__tblr_tracing_intarray_bool
+    \bool_gset_false:N \g__tblr_tracing_page_bool
+    \bool_gset_false:N \g__tblr_tracing_step_bool
   }
 
 \NewDocumentCommand \LogTabularrayTracing { m }
@@ -4459,6 +6369,7 @@
 
 \keys_define:nn { tblr-log-tracing }
   {
+    step .code:n = \__tblr_log_tracing_step:n {#1},
     unknown .code:n = \__tblr_log_tracing:N \l_keys_key_str
   }
 
@@ -4470,7 +6381,7 @@
 
 \cs_new_protected:Npn \__tblr_log_tracing_text:
   {
-    \__tblr_text_log:n { text }
+    \__tblr_spec_log:n { text }
   }
 
 \cs_new_protected:Npn \__tblr_log_tracing_command:
@@ -4478,11 +6389,28 @@
     \__tblr_prop_log:n { command }
   }
 
-\cs_new_protected:Npn \__tblr_log_tracing_table:
+\cs_new_protected:Npn \__tblr_log_tracing_option:
   {
-    \__tblr_prop_log:n { table }
+    \__tblr_prop_log:n { note }
+    \__tblr_prop_log:n { remark }
+    \__tblr_prop_log:n { more }
   }
 
+\cs_new_protected:Npn \__tblr_log_tracing_theme:
+  {
+    \__tblr_style_log:
+  }
+
+\cs_new_protected:Npn \__tblr_log_tracing_outer:
+  {
+    \__tblr_spec_log:n { outer }
+  }
+
+\cs_new_protected:Npn \__tblr_log_tracing_inner:
+  {
+    \__tblr_prop_log:n { inner }
+  }
+
 \cs_new_protected:Npn \__tblr_log_tracing_column:
   {
     \__tblr_data_log:n { column }
@@ -4500,12 +6428,12 @@
 
 \cs_new_protected:Npn \__tblr_log_tracing_vline:
   {
-    \__tblr_text_log:n { vline }
+    \__tblr_spec_log:n { vline }
   }
 
 \cs_new_protected:Npn \__tblr_log_tracing_hline:
   {
-    \__tblr_text_log:n { hline }
+    \__tblr_spec_log:n { hline }
   }
 
 \cs_new_protected:Npn \__tblr_log_tracing_colspec:
@@ -4537,9 +6465,279 @@
     \prop_log:N \l__tblr_row_span_to_row_prop
   }
 
+\cs_new_protected:Npn \__tblr_log_tracing_page:
+  {
+    \dim_log:N \pagegoal
+    \dim_log:N \pagetotal
+  }
+
+\cs_new_protected:Npn \__tblr_log_tracing_step:n #1
+  {
+    \bool_if:NT \g__tblr_tracing_step_bool { \tl_log:x {Step :~ #1} }
+  }
+
 \cs_new_protected:Npn \__tblr_do_if_tracing:nn #1 #2
   {
     \bool_if:cT { g__tblr_tracing_ #1 _bool } {#2}
   }
 
-\ExplSyntaxOff
+%%% --------------------------------------------------------
+%%  \section{Tabularray Libraries}
+%%% --------------------------------------------------------
+
+%% \NewTblrLibrary and \UseTblrLibrary commands
+
+\NewDocumentCommand \NewTblrLibrary { m m }
+  {
+    \cs_new_protected:cpn { __tblr_use_lib_ #1: } {#2}
+  }
+
+\NewDocumentCommand \UseTblrLibrary { m }
+  {
+    \clist_map_inline:nn {#1} { \use:c { __tblr_use_lib_ ##1: } }
+  }
+
+%% Library amsmath and environments +array, +matrix, +cases, ...
+
+\NewTblrLibrary { amsmath }
+  {
+    \RequirePackage { amsmath, environ }
+    \NewTblrEnviron { +array }
+    \SetTblrInner[+array]{colsep = 5pt}
+    \NewEnviron { +matrix } [1] [] {
+      \begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}
+    }
+    \NewEnviron { +bmatrix } [1] [] {
+      \left[\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}\right]
+      \ignorespacesafterend
+    }
+    \NewEnviron { +Bmatrix } [1] [] {
+      \left\lbrace\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}\right\rbrace
+    }
+    \NewEnviron { +pmatrix } [1] [] {
+      \left(\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}\right)
+    }
+    \NewEnviron { +vmatrix } [1] [] {
+      \left\lvert\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}\right\rvert
+    }
+    \NewEnviron { +Vmatrix } [1] [] {
+      \left\lVert\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        cells = {c}, ##1
+      }
+        \BODY
+      \end{+array}\right\rVert
+    }
+    \NewEnviron { +cases } [1] [] {
+      \left\lbrace\begin{+array}[expand = \BODY]{
+        column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
+        colspec = {ll}, stretch = 1.2, ##1
+      }
+        \BODY
+      \end{+array}\right.
+    }
+  }
+
+%% Library booktabs and commands \toprule, \midrule, \bottomrule
+
+\NewTblrLibrary { booktabs }
+  {
+    % We only use dimensions \aboverulesep and \belowrulesep in booktabs package
+    \RequirePackage { booktabs }
+    \newcommand \tblr at booktabs@hline [1] [] { \hline [##1] }
+    \newcommand \tblr at booktabs@oldhline [1] [] {
+      \hline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1]
+    }
+    \newcommand \tblr at booktabs@cline [2] [] { \cline [##1] {##2} }
+    \newcommand \tblr at booktabs@oldcline [2] [] {
+      \cline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] {##2}
+    }
+    \newcommand \tblr at booktabs@cline at more [2] [] { \SetHline [+] {##2} {##1} }
+    \newcommand \tblr at booktabs@oldcline at more [2] [] {
+      \SetHline [+] {##2} {
+        abovespace = \aboverulesep, belowspace = \belowrulesep, ##1
+      }
+    }
+    \NewTableCommand \toprule [1] [] {
+      \tblr at booktabs@hline [wd=\heavyrulewidth, ##1]
+    }
+    \NewTableCommand \midrule [1] [] {
+      \tblr at booktabs@hline [wd=\lightrulewidth, ##1]
+    }
+    \NewTableCommand \bottomrule [1] [] {
+      \tblr at booktabs@hline [wd=\heavyrulewidth, ##1]
+    }
+    \NewTableCommand \cmidrule [2] [] {
+      \tblr at booktabs@cline [wd=\cmidrulewidth, endpos, ##1] {##2}
+    }
+    \NewTableCommand \cmidrulemore [2] [] {
+      \tblr at booktabs@cline at more [wd=\cmidrulewidth, endpos, ##1] {##2}
+    }
+    \newcommand \tblr at booktabs@change at more [1] { \cmidrulemore }
+    \NewTableCommand \morecmidrules {
+      \peek_meaning:NTF \cmidrule { \tblr at booktabs@change at more } { \relax }
+    }
+    \NewTblrEnviron { booktabs }
+    \SetTblrInner [ booktabs ] { rowsep = 0pt }
+    \RequirePackage { etoolbox }
+    \AtBeginEnvironment { booktabs }
+      {
+        \let \tblr at booktabs@hline = \tblr at booktabs@oldhline
+        \let \tblr at booktabs@cline = \tblr at booktabs@oldcline
+        \let \tblr at booktabs@cline at more = \tblr at booktabs@oldcline at more
+      }
+    \NewTableCommand \specialrule [3]
+      { \hline [##1, abovespace = ##2, belowspace = ##3] }
+    \NewTableCommand \addrowspace [1] [\defaultaddspace]
+      { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
+    \NewTableCommand \addlinespace [1] [\defaultaddspace]
+      { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
+  }
+
+%% Library counter for resetting all counters
+
+\tl_new:N \__tblr_saved_trial_counters_tl
+\tl_new:N \__tblr_saved_cell_counters_tl
+
+\cs_new_protected:Npn \__tblr_save_counters:n #1 { }
+\cs_new_protected:Npn \__tblr_restore_counters:n #1 { }
+
+%% We use code from tabularx package for resetting all LaTeX counters,
+%% where internal macro \cl@@ckpt looks like the following:
+%% \@elt{page} \@elt{equation} \@elt{enumi} \@elt{enumii} \@elt{enumiii} ...
+
+\NewTblrLibrary { counter }
+  {
+    \cs_set_protected:Npn \__tblr_save_counters:n ##1
+      {
+        \def \@elt ####1 { \global\value{####1} = \the\value{####1} \relax }
+        \tl_set:cx { __tblr_saved_ ##1 _counters_tl } { \cl@@ckpt }
+        \let \@elt = \relax
+      }
+    \cs_set_protected:Npn \__tblr_restore_counters:n ##1
+      {
+        \tl_use:c { __tblr_saved_ ##1 _counters_tl }
+      }
+  }
+
+%% Library diagbox and command \diagbox
+
+\NewTblrLibrary { diagbox }
+  {
+    \RequirePackage{ diagbox }
+    \cs_set_eq:NN \__tblr_lib_saved_diagbox:w \diagbox
+    \NewContentCommand \diagbox [3] []
+      {
+        \__tblr_lib_diagbox_fix:n
+          {
+            \__tblr_lib_saved_diagbox:w
+              [ leftsep=\leftsep, rightsep=\rightsep, ##1 ]
+              { \__tblr_lib_diagbox_math_or_text:n {##2} }
+              { \__tblr_lib_diagbox_math_or_text:n {##3} }
+          }
+      }
+    \NewContentCommand \diagboxthree [4] []
+      {
+        \__tblr_lib_diagbox_fix:n
+          {
+            \__tblr_lib_saved_diagbox:w
+              [ leftsep=\leftsep, rightsep=\rightsep, ##1 ]
+              { \__tblr_lib_diagbox_math_or_text:n {##2} }
+              { \__tblr_lib_diagbox_math_or_text:n {##3} }
+              { \__tblr_lib_diagbox_math_or_text:n {##4} }
+          }
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_lib_diagbox_math_or_text:n #1
+  {
+    \bool_if:NTF \l__tblr_cell_math_mode_bool {$#1$} {#1}
+  }
+
+\box_new:N \l__tblr_diag_box
+
+\cs_new_protected:Npn \__tblr_lib_diagbox_fix:n #1
+  {
+    \hbox_set:Nn \l__tblr_diag_box {#1}
+    \box_set_ht:Nn \l__tblr_diag_box { \box_ht:N \l__tblr_diag_box - \abovesep }
+    \box_set_dp:Nn \l__tblr_diag_box { \box_dp:N \l__tblr_diag_box - \belowsep }
+    \box_use:N \l__tblr_diag_box
+  }
+
+%% Library siunitx and S columns
+
+\NewTblrLibrary { siunitx }
+  {
+    \RequirePackage { siunitx }
+    \NewColumnType { S } [1] [] { Q[si = {##1}, c] }
+    \NewColumnType { s } [1] [] { Q[si = {##1}, c, cmd = \TblrUnit] }
+    \__tblr_data_new_key:nnn { cell } { si } { str }
+    \keys_define:nn { tblr-column }
+      {
+        si .code:n = \__tblr_siunitx_setcolumn:n {##1}
+      }
+    \cs_new_protected:Npn \__tblr_siunitx_setcolumn:n ##1
+      {
+        \__tblr_column_gput_cell:nn { si } {##1}
+        \__tblr_column_gput_cell:nn { cmd } { \TblrNum }
+      }
+    \NewDocumentCommand \TblrNum { m }
+      {
+        \__tblr_siunitx_process:Nn \tablenum {##1}
+      }
+    \NewDocumentCommand \TblrUnit { m }
+      {
+        \__tblr_siunitx_process:Nn \si {##1}
+      }
+    \cs_new_protected:Npn \__tblr_siunitx_process:Nn ##1 ##2
+      {
+        \tl_if_head_is_group:nTF {##2}
+          { ##2 }
+          {
+            \group_begin:
+            \tl_set:Nx \l_tmpa_tl
+              {
+                \__tblr_data_item:neen { cell }
+                  { \int_use:N \c at rownum } { \int_use:N \c at colnum } { si }
+              }
+            \exp_args:NV \sisetup \l_tmpa_tl
+            ##1 {##2}
+            \group_end:
+          }
+      }
+  }
+
+%% Library varwidth and measure option
+
+\NewTblrLibrary { varwidth }
+  {
+    \RequirePackage { varwidth }
+    \clist_gput_left:Nn \g__tblr_table_known_keys_clist { measure }
+    \keys_define:nn { tblr } { measure .tl_set:N = \l__tblr_inner_spec_measure_tl }
+  }
+

Modified: trunk/Master/texmf-dist/tex/latex/tabularray/tabularray.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/tabularray/tabularray.sty	2022-03-01 21:52:45 UTC (rev 62327)
+++ trunk/Master/texmf-dist/tex/latex/tabularray/tabularray.sty	2022-03-01 21:53:05 UTC (rev 62328)
@@ -1,49 +1,65 @@
 %%% % -*- coding: utf-8 -*-
 %%% ----------------------------------------------------------------------------
 %%% Tabularray: Typeset tabulars and arrays with LaTeX3
-%%% Author    : Jianrui Lyu <tolvjr at 163.com>
+%%% Copyright : 2021-2022 (c) Jianrui Lyu <tolvjr at 163.com>
 %%% Repository: https://github.com/lvjr/tabularray
 %%% License   : The LaTeX Project Public License 1.3
 %%% ----------------------------------------------------------------------------
 
 %%% --------------------------------------------------------
-%%  \section{Scratch Variables and Function Variants}
+%%> \section{Scratch Variables and Function Variants}
 %%% --------------------------------------------------------
 
-\NeedsTeXFormat{LaTeX2e}
+%% \DeclareRelease and \DeclareCurrentRelease are added in LaTeX 2018-04-01
+\NeedsTeXFormat{LaTeX2e}[2018-04-01]
+\DeclareRelease{v2021}{}{tabularray-2021.sty}
+\DeclareCurrentRelease{}{2022-01-01}
+
 \RequirePackage{expl3}
-\ProvidesExplPackage{tabularray}{2021-12-01}{2021Q}
+\ProvidesExplPackage{tabularray}{2022-03-01}{2022A}
   {Typeset tabulars and arrays with LaTeX3}
 
-\RequirePackage{xparse}
-
-\AtBeginDocument{\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}}
-
-%% Backport \tl_if_eq:NnTF for old texlive 2020
-\cs_if_exist:NF \tl_if_eq:NnTF
+%% \IfFormatAtLeastTF, xparse and lthooks are added in LaTeX 2020-10-01
+%% Note that \@ifl at t@r or \@ifpackagelater means 'this date or later'
+\msg_new:nnn { tabularray } { latex-too-old }
   {
-    \tl_new:N \l__tblr_backport_b_tl
-    \prg_new_protected_conditional:Npnn \tl_if_eq:Nn #1 #2 { T, F, TF }
-      {
-        \group_begin:
-          \tl_set:Nn \l__tblr_backport_b_tl {#2}
-          \exp_after:wN
-        \group_end:
-        \if_meaning:w #1 \l__tblr_backport_b_tl
-          \prg_return_true:
-        \else:
-          \prg_return_false:
-        \fi:
-      }
-    \prg_generate_conditional_variant:Nnn \tl_if_eq:Nn { c } { TF, T, F }
+    Your ~ LaTeX ~ release ~ is ~ too ~ old. \\
+    Please ~ update ~ to ~ 2020-10-01 ~ first.
   }
+\@ifl at t@r\fmtversion{2020-10-01}{}{
+  %% Support TeX Live 2020 on Overleaf
+  \msg_warning:nn { tabularray } { latex-too-old }
+  \usepackage{xparse}
+}
 
-%% Compatible with texlive 2020
-\cs_if_exist:NF \seq_map_indexed_function:NN
+\AtBeginDocument{
+  \@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}
+  \@ifpackageloaded{hyperref}{
+    \newenvironment{tblrNoHyper}{\NoHyper}{\endNoHyper}
+  }{
+    \newenvironment{tblrNoHyper}{}{}
+  }
+}
+
+\NewDocumentCommand \TblrParboxRestore { } { \@parboxrestore }
+
+\NewDocumentCommand \TblrAlignBoth { }
   {
-    \cs_set_eq:NN \seq_map_indexed_function:NN \seq_indexed_map_function:NN
+    \let \\ = \@normalcr
+    \leftskip = \z at skip
+    \@rightskip = \z at skip
+    \rightskip = \@rightskip
+    \parfillskip = \@flushglue
   }
 
+\NewDocumentCommand \TblrAlignLeft { } { \raggedright }
+
+\NewDocumentCommand \TblrAlignCenter { } { \centering }
+
+\NewDocumentCommand \TblrAlignRight { } { \raggedleft }
+
+\cs_set_eq:NN \TblrNewPage \newpage
+
 \cs_generate_variant:Nn \msg_error:nnnn { nnVn }
 \cs_generate_variant:Nn \prop_item:Nn { Ne, NV }
 \cs_generate_variant:Nn \prop_put:Nnn { Nxn, Nxx, NxV }
@@ -55,6 +71,7 @@
 \cs_generate_variant:Nn \tl_put_left:Nn { Nv }
 \prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF }
 \prg_generate_conditional_variant:Nnn \prop_if_in:Nn { c } { T }
+\prg_generate_conditional_variant:Nnn \regex_match:Nn { NV } { TF }
 \prg_generate_conditional_variant:Nnn \str_if_eq:nn { xn } { TF }
 \prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T, TF }
 \prg_generate_conditional_variant:Nnn \tl_if_head_eq_catcode:nN { VN } { TF }
@@ -102,9 +119,10 @@
 \int_new:N \g__tblr_table_count_int
 
 %% Some commands for horizontal alignment
-\cs_new_eq:NN \__tblr_halign_command_l: \raggedright
-\cs_new_eq:NN \__tblr_halign_command_c: \centering
-\cs_new_eq:NN \__tblr_halign_command_r: \raggedleft
+\cs_new_eq:NN \__tblr_halign_command_j: \TblrAlignBoth
+\cs_new_eq:NN \__tblr_halign_command_l: \TblrAlignLeft
+\cs_new_eq:NN \__tblr_halign_command_c: \TblrAlignCenter
+\cs_new_eq:NN \__tblr_halign_command_r: \TblrAlignRight
 
 %% Some counters for row and column numbering.
 %% We may need to restore all LaTeX counters in measuring and building cells,
@@ -127,7 +145,7 @@
 \dim_new:N \rightsep
 
 %%% --------------------------------------------------------
-%%  \section{Data Structures Based on Property Lists}
+%%> \section{Data Structures Based on Property Lists}
 %%% --------------------------------------------------------
 
 \int_new:N \g_tblr_level_int % store table nesting level
@@ -238,7 +256,7 @@
 \cs_generate_variant:Nn \__tblr_gadd_dimen_value:Nnn { cnn }
 
 %%% --------------------------------------------------------
-%%  \section{Data Structures Based on Token Lists}
+%%> \section{Data Structures Based on Token Lists}
 %%% --------------------------------------------------------
 
 \cs_new_protected:Npn \__tblr_clear_spec_lists:
@@ -318,7 +336,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Data Structures Based on Integer Arrays}
+%%> \section{Data Structures Based on Integer Arrays}
 %%% --------------------------------------------------------
 
 \msg_new:nnn { tabularray } { intarray-beyond-bound }
@@ -362,7 +380,6 @@
 \__tblr_data_new_key:nnn { row } { @row-foot }   { dim }
 \__tblr_data_new_key:nnn { row } { @row-upper }  { dim }
 \__tblr_data_new_key:nnn { row } { @row-lower }  { dim }
-\__tblr_data_new_key:nnn { row } { break }       { int }
 
 \int_new:N \g__tblr_data_column_key_count_int
 \__tblr_data_new_key:nnn { column } { width }       { dim }
@@ -763,7 +780,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Child Selectors}
+%%> \section{Child Selectors}
 %%% --------------------------------------------------------
 
 \clist_new:N \g_tblr_used_child_selectors_clist
@@ -810,15 +827,42 @@
 \clist_new:N \l_tblr_childs_clist
 \tl_new:N \l_tblr_childs_total_tl
 
-\NewChildSelector { odd }
+\NewChildSelector { odd } [1] []
   {
-    \int_step_inline:nnnn {1} {2} { \l_tblr_childs_total_tl }
-      { \clist_put_right:Nn \l_tblr_childs_clist {##1} }
+    \tl_if_blank:nTF {#1}
+      {
+        \int_step_inline:nnnn {1} {2} { \l_tblr_childs_total_tl }
+          { \clist_put_right:Nn \l_tblr_childs_clist {##1} }
+      }
+      { \__tblr_child_selector_odd_or_even:nn { odd } {#1} }
   }
 
-\NewChildSelector { even }
+\NewChildSelector { even } [1] []
   {
-    \int_step_inline:nnnn {2} {2} { \l_tblr_childs_total_tl }
+    \tl_if_blank:nTF {#1}
+      {
+        \int_step_inline:nnnn {2} {2} { \l_tblr_childs_total_tl }
+          { \clist_put_right:Nn \l_tblr_childs_clist {##1} }
+      }
+      { \__tblr_child_selector_odd_or_even:nn { even } {#1} }
+  }
+
+\tl_new:N \l__tblr_child_from_tl
+\tl_new:N \l__tblr_child_to_tl
+
+%% #1: odd or even; #2: selector option
+\cs_new_protected:Npn \__tblr_child_selector_odd_or_even:nn #1 #2
+  {
+    \seq_set_split:Nnn \l_tmpa_seq {-} { #2 - Z }
+    \tl_set:Nx \l__tblr_child_from_tl { \seq_item:Nn \l_tmpa_seq {1} }
+    \tl_set:Nx \l__tblr_child_to_tl { \seq_item:Nn \l_tmpa_seq {2} }
+    \tl_use:c { int_if_ #1 :nF } { \l__tblr_child_from_tl }
+      {
+        \tl_set:Nx \l__tblr_child_from_tl
+          { \int_eval:n { \l__tblr_child_from_tl + 1 } }
+      }
+    \__tblr_child_name_to_index:VN \l__tblr_child_to_tl \l__tblr_child_to_tl
+    \int_step_inline:nnnn { \l__tblr_child_from_tl } {2} { \l__tblr_child_to_tl }
       { \clist_put_right:Nn \l_tblr_childs_clist {##1} }
   }
 
@@ -842,7 +886,7 @@
             __tblr_child_selector_ \seq_item:Nn \l__tblr_childs_regex_seq {2} :w
             \cs_end:
           }
-        \exp_args:Nx \l__tblr_childs_selector_tl
+        \exp_last_unbraced:Nx \l__tblr_childs_selector_tl
           { \seq_item:Nn \l__tblr_childs_regex_seq{3} }
       }
       {
@@ -865,9 +909,6 @@
       }
   }
 
-\tl_new:N \l__tblr_child_from_tl
-\tl_new:N \l__tblr_child_to_tl
-
 \cs_new_protected_nopar:Npn \__tblr_get_childs_normal_aux:w #1 - #2 \scan_stop
   {
     \__tblr_child_name_to_index:nN {#1} \l__tblr_child_from_tl
@@ -888,9 +929,10 @@
       }
       { \tl_set:Nx #2 { #1 } }
   }
+\cs_generate_variant:Nn \__tblr_child_name_to_index:nN { VN }
 
 %%% --------------------------------------------------------
-%%  \section{New Table Commands}
+%%> \section{New Table Commands}
 %%% --------------------------------------------------------
 
 %% We need some commands to modify table/row/column/cell specifications.
@@ -985,7 +1027,7 @@
   {
     \clist_if_in:NnTF \g__tblr_content_commands_clist { #1 }
       {
-        \msg_warning:nnn { tabularray } { defined-content-command } { #1 }
+        \msg_error:nnn { tabularray } { defined-content-command } { #1 }
         \clist_log:N \g__tblr_content_commands_clist
       }
       {
@@ -1003,7 +1045,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{New Dash Styles}
+%%> \section{New Dash Styles}
 %%% --------------------------------------------------------
 
 %% \NewDashStyle commands
@@ -1073,7 +1115,7 @@
 \NewDashStyle {dotted} {on ~ 0.4pt ~ off ~ 1pt}
 
 %%% --------------------------------------------------------
-%%  \section{Set Hlines and Vlines}
+%%> \section{Set Hlines and Vlines}
 %%% --------------------------------------------------------
 
 \tl_set:Nn \@tblr at dash { dash }
@@ -1128,10 +1170,6 @@
 
 \NewTableCommand \hline [1] [] { \SetHline [+] {-} {#1} }
 
-%% Some keys can be set by any hline, such as abovespace and belowspace keys.
-%% Using special hline of index 0, you can set these keys without adding any hlines.
-\NewTableCommand \SetVspace [1] { \SetHline [0] {-} {#1} }
-
 %% #1: the index of the hline (may be + or =)
 %% #2: which columns of the hline, separate by commas
 %% #3: key=value pairs
@@ -1145,19 +1183,13 @@
 \cs_new_protected:Npn \tblr_set_hline:nnn #1 #2 #3
   {
     \group_begin:
-    %% We can not use \int_compare:nNnTF here since #1 may be + or = .
-    %% Also we treat hline of index 0 specially, not adding hline count.
-    \tl_if_eq:nnTF {#1} {0}
-      { \keys_set:nn { tblr-hline } {#3} }
+    \keys_set_groups:nnn { tblr-hline } { text } {#3}
+    \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr at text }
       {
-        \keys_set_groups:nnn { tblr-hline } { text } {#3}
-        \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr at text }
-          {
-            \__tblr_set_hline_num:n {#1}
-            \tl_clear:N \l__tblr_hline_dash_tl
-            \keys_set:nn { tblr-hline } { dash = solid, #3 }
-            \__tblr_set_hline_cmd:n {#2}
-          }
+        \__tblr_set_hline_num:n {#1}
+        \tl_clear:N \l__tblr_hline_dash_tl
+        \keys_set:nn { tblr-hline } { dash = solid, #3 }
+        \__tblr_set_hline_cmd:n {#2}
       }
     \group_end:
   }
@@ -1233,7 +1265,6 @@
     text .groups:n = { text },
     wd .code:n = \tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {#1} },
     fg .code:n = \tl_set:Nn \l__tblr_hline_fg_tl {#1},
-    baseline .code:n = \__tblr_hline_set_baseline:n {#1},
     leftpos  .code:n = \tl_set:Nx \l__tblr_hline_leftpos_tl {#1},
     rightpos .code:n = \tl_set:Nx \l__tblr_hline_rightpos_tl {#1},
     l        .meta:n = { leftpos = #1 },
@@ -1243,12 +1274,6 @@
     lr       .meta:n = { leftpos = #1, rightpos = #1 },
     lr    .default:n = { -0.8 },
     endpos .bool_set:N = \l__tblr_hline_endpos_bool,
-    abovespace .code:n = \__tblr_row_gput_above:ne { belowsep } { \dim_eval:n {#1} },
-    belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
-    abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne
-                          { belowsep } { \dim_eval:n {#1} },
-    belowspace+ .code:n = \__tblr_row_gadd_dimen:ne
-                          { abovesep } { \dim_eval:n {#1} },
     unknown .code:n = \__tblr_hline_unknown_key:V \l_keys_key_str,
   }
 
@@ -1325,24 +1350,22 @@
       { [\int_use:N \c at rownum][#1](\l__tblr_hline_num_tl) / #2 } { #3 }
   }
 
-\NewTableCommand \firsthline [1] [] { \SetHline [+] {-} { #1, baseline=below } }
-\NewTableCommand \lasthline [1] [] { \SetHline [+] {-} { #1, baseline=above } }
+\msg_new:nnn { tabularray } { obsolete-firsthline }
+  { \firsthline ~ is ~ obsolete; ~ use ~ 'baseline=T' ~ instead. }
 
-\cs_new_protected:Npn \__tblr_hline_set_baseline:n #1
+\msg_new:nnn { tabularray } { obsolete-lasthline }
+  { \lasthline ~ is ~ obsolete; ~ use ~ 'baseline=B' ~ instead. }
+
+\NewTableCommand \firsthline [1] []
   {
-    \tl_if_eq:nnTF {#1} {above}
-      {
-        \__tblr_prop_gput:nnx { inner }
-          { baseline } { \int_eval:n { \c at rownum - 1 } }
-      }
-      {
-        \tl_if_eq:nnT {#1} {below}
-          {
-            \__tblr_prop_gput:nnx { inner } { baseline } { \int_use:N \c at rownum }
-          }
-      }
+    \msg_error:nn { tabularray } { obsolete-firsthline }
   }
 
+\NewTableCommand \lasthline [1] []
+  {
+    \msg_error:nn { tabularray } { obsolete-lasthline }
+  }
+
 %% \SetVlines command for setting every vline in the table
 \NewTableCommand \SetVlines [3] [+]
   {
@@ -1540,9 +1563,109 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Set Cells}
+%%>  \section{Set Hborders and Vborders}
 %%% --------------------------------------------------------
 
+%% Hborder holds keys not related to a specified hline
+\NewTableCommand \hborder [1] { \tblr_set_hborder:n {#1} }
+
+\cs_new_protected:Npn \tblr_set_hborder:n #1
+  {
+    \keys_set:nn { tblr-hborder } {#1}
+  }
+
+\cs_new_protected:Npn \tblr_set_hborder:nn #1 #2
+  {
+    \group_begin:
+    \__tblr_get_childs:nx {#1} { \int_eval:n { \c at rowcount + 1 } }
+    \clist_map_inline:Nn \l_tblr_childs_clist
+      {
+        \int_set:Nn \c at rownum {##1}
+        \tblr_set_hborder:n {#2}
+      }
+    \group_end:
+  }
+
+%% This function is called when parsing table specifications
+%% Note that #1 always includes an outer pair of braces
+\cs_new_protected:Npn \__tblr_set_hborder_aux:nn #1 #2
+  {
+    \tblr_set_hborder:nn #1 {#2}
+  }
+\cs_generate_variant:Nn \__tblr_set_hborder_aux:nn { Vn }
+
+\keys_define:nn { tblr-hborder }
+  {
+    abovespace .code:n = \__tblr_row_gput_above:ne
+                          { belowsep } { \dim_eval:n {#1} },
+    belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
+    abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne
+                          { belowsep } { \dim_eval:n {#1} },
+    belowspace+ .code:n = \__tblr_row_gadd_dimen:ne
+                          { abovesep } { \dim_eval:n {#1} },
+    pagebreak   .code:n = \__tblr_hborder_gput_pagebreak:n {#1},
+    pagebreak   .default:n = yes,
+    baseline    .code:n = \__tblr_outer_gput_spec:ne
+                          { baseline } { - \int_use:N \c at rownum },
+  }
+
+\tl_const:Nn \c__tblr_pagebreak_yes_tl  {  1 }
+\tl_const:Nn \c__tblr_pagebreak_auto_tl {  0 }
+\tl_const:Nn \c__tblr_pagebreak_no_tl   { -1 }
+
+\cs_new_protected:Npn \__tblr_hborder_gput_pagebreak:n #1
+  {
+    \tl_if_exist:cT { c__tblr_pagebreak_ #1 _tl }
+      {
+        \__tblr_spec_gput:nee { hline }
+          { [\int_use:N \c at rownum] / @pagebreak }
+          { \tl_use:c { c__tblr_pagebreak_ #1 _tl } }
+      }
+  }
+
+%% Vborder holds keys not related to a specified vline
+\NewTableCommand \vborder [1] { \tblr_set_vborder:n {#1} }
+
+\cs_new_protected:Npn \tblr_set_vborder:n #1
+  {
+    \keys_set:nn { tblr-vborder } {#1}
+  }
+
+\cs_new_protected:Npn \tblr_set_vborder:nn #1 #2
+  {
+    \group_begin:
+    \__tblr_get_childs:nx {#1} { \int_eval:n { \c at colcount + 1 } }
+    \clist_map_inline:Nn \l_tblr_childs_clist
+      {
+        \int_set:Nn \c at colnum {##1}
+        \tblr_set_vborder:n {#2}
+      }
+    \group_end:
+  }
+
+%% This function is called when parsing table specifications
+%% Note that #1 always includes an outer pair of braces
+\cs_new_protected:Npn \__tblr_set_vborder_aux:nn #1 #2
+  {
+    \tblr_set_vborder:nn #1 {#2}
+  }
+\cs_generate_variant:Nn \__tblr_set_vborder_aux:nn { Vn }
+
+\keys_define:nn { tblr-vborder }
+  {
+    leftspace .code:n = \__tblr_column_gput_left:ne
+                          { rightsep } { \dim_eval:n {#1} },
+    rightspace .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} },
+    leftspace+ .code:n = \__tblr_column_gadd_dimen_left:ne
+                          { rightsep } { \dim_eval:n {#1} },
+    rightspace+ .code:n = \__tblr_column_gadd_dimen:ne
+                          { leftsep } { \dim_eval:n {#1} },
+  }
+
+%%% --------------------------------------------------------
+%%> \section{Set Cells}
+%%% --------------------------------------------------------
+
 %% \SetCells command for setting every cell in the table
 \NewTableCommand \SetCells [2] []
   {
@@ -1767,7 +1890,7 @@
           { 1 }
       }
     \int_step_variable:nnNn
-      { \c at rownum } { \int_eval:n { \c at rownum + #1 -1 } } \l__tblr_i_tl
+      { \c at rownum } { \int_eval:n { \c at rownum + #1 - 2 } } \l__tblr_i_tl
       {
         \__tblr_spec_gput:nee { vline }
           { [\l__tblr_i_tl][\int_use:N \c at colnum](\l__tblr_n_tl) / belowpos } {1}
@@ -1777,59 +1900,26 @@
   }
 \cs_generate_variant:Nn \__tblr_set_span_spec:nn { VV }
 
-%% Legacy \multicolumn and \multirow commands
-%% Both of them could be replaced with \SetCell command
-%% Note that they don't have cell text as the last arguments
+%% Obsolete \multicolumn and \multirow commands
 
-%% If \multicolumn is followed by \multirow,
-%% We need to call \tblr_set_cell together
-%% in order to omit all hlines inside the span cell.
-\tl_new:N \g__tblr_multicolumn_num_tl
-\tl_new:N \g__tblr_multicolumn_spec_tl
+\msg_new:nnn { tabularray } { obsolete-multicolumn }
+  { \multicolumn ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. }
 
-%% There maybe p{2em} inside #2 of \multicolumn command
+\msg_new:nnn { tabularray } { obsolete-multirow }
+  { \multirow ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. }
+
 \NewTableCommand \multicolumn [2]
   {
-    \tl_gclear:N \g__tblr_multicolumn_num_tl
-    \tl_gclear:N \g__tblr_multicolumn_spec_tl
-    \tl_map_inline:nn {#2}
-      {
-        \bool_lazy_and:nnF
-          { \tl_if_single_token_p:n {##1} }
-          { \token_if_eq_charcode_p:NN ##1 | }
-          { \tl_put_right:Nn \g__tblr_multicolumn_spec_tl {,##1} }
-      }
-    \peek_meaning:NTF \multirow
-      { \tl_gset:Nn \g__tblr_multicolumn_num_tl {#1} }
-      { \tblr_set_cell:nV { c = #1 } \g__tblr_multicolumn_spec_tl }
+    \msg_error:nn { tabularray } { obsolete-multicolumn }
   }
 
 \NewTableCommand \multirow [3] [m]
   {
-    \tl_if_eq:nnTF {#1} {c}
-      { \tl_set:Nn \l_tmpa_tl {, m} }
-      {
-        \tl_if_eq:nnTF {#1} {t}
-          { \tl_set:Nn \l_tmpa_tl {, h} }
-          { \tl_if_eq:nnTF {#1} {b}
-            { \tl_set:Nn \l_tmpa_tl {, f} }
-            { \tl_set:Nn \l_tmpa_tl {, #1} }
-          }
-      }
-    \tl_if_eq:nnF {#3} {*}
-      { \tl_if_eq:nnF {#3} {=} { \tl_put_right:Nn \l_tmpa_tl {, wd=#3} } }
-    \tl_if_empty:NTF \g__tblr_multicolumn_num_tl
-      { \tblr_set_cell:nV { r = #2 } \l_tmpa_tl }
-      {
-        \tl_put_left:NV \l_tmpa_tl \g__tblr_multicolumn_spec_tl
-        \exp_args:Nx \tblr_set_cell:nV
-          { c = \g__tblr_multicolumn_num_tl, r = #2 } \l_tmpa_tl
-        \tl_gclear:N \g__tblr_multicolumn_num_tl
-      }
+    \msg_error:nn { tabularray } { obsolete-multirow }
   }
 
 %%% --------------------------------------------------------
-%%  \section{Set Columns and Rows}
+%%> \section{Set Columns and Rows}
 %%% --------------------------------------------------------
 
 %% \SetColumns command for setting every column in the table
@@ -1937,6 +2027,12 @@
   }
 \cs_generate_variant:Nn \__tblr_column_gput:nn { ne }
 
+\cs_new_protected:Npn \__tblr_column_gput_left:nn #1 #2
+  {
+    \__tblr_data_gput:nenn { column } { \int_eval:n { \c at colnum - 1 } } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_column_gput_left:nn { ne }
+
 \cs_new_protected:Npn \__tblr_column_gadd_dimen:nn #1 #2
   {
     \__tblr_data_gadd_dimen_value:nenn { column }
@@ -1944,6 +2040,13 @@
   }
 \cs_generate_variant:Nn \__tblr_column_gadd_dimen:nn { ne }
 
+\cs_new_protected:Npn \__tblr_column_gadd_dimen_left:nn #1 #2
+  {
+    \__tblr_data_gadd_dimen_value:nenn { column }
+      { \int_eval:n { \c at colnum - 1 } } {#1} {#2}
+  }
+\cs_generate_variant:Nn \__tblr_column_gadd_dimen_left:nn { ne }
+
 %% #1: key; #2: value
 \cs_new_protected:Npn \__tblr_column_gput_cell:nn #1 #2
   {
@@ -2080,9 +2183,8 @@
     abovesep+ .code:n = \__tblr_row_gadd_dimen:ne { abovesep } { \dim_eval:n {#1} },
     belowsep+ .code:n = \__tblr_row_gadd_dimen:ne { belowsep } { \dim_eval:n {#1} },
     rowsep+   .meta:n = { abovesep+ = #1, belowsep+ = #1},
-    break     .code:n = \__tblr_row_gput:nn { break } {#1},
-    pagebreak   .meta:n = { break = 1 },
-    nopagebreak .meta:n = { break = -1 },
+    baseline  .code:n = \__tblr_outer_gput_spec:ne
+                          { baseline } { \int_use:N \c at rownum },
     unknown   .code:n = \__tblr_row_unknown_key:V \l_keys_key_str,
   }
 
@@ -2158,16 +2260,16 @@
 
 \NewTableCommand \pagebreak
   {
-    \tblr_set_row:nn {} { break = 1 }
+    \hborder { pagebreak = yes }
   }
 
 \NewTableCommand \nopagebreak
   {
-    \tblr_set_row:nn {} { break = -1 }
+    \hborder { pagebreak = no }
   }
 
 %%% --------------------------------------------------------
-%%  \section{Column Types and Row Types}
+%%> \section{Column Types and Row Types}
 %%% --------------------------------------------------------
 
 %% Some primitive column/row types
@@ -2344,8 +2446,8 @@
     \str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1}
       {
         \tl_if_eq:NnTF \g__tblr_column_or_row_tl { row }
-          { \msg_warning:nnnn { tabularray } { used-colrow-type } { Row } {#1} }
-          { \msg_warning:nnnn { tabularray } { used-colrow-type } { Column } {#1} }
+          { \msg_error:nnnn { tabularray } { used-colrow-type } { Row } {#1} }
+          { \msg_error:nnnn { tabularray } { used-colrow-type } { Column } {#1} }
         \str_log:c { g_tblr_used_ \g__tblr_column_or_row_tl _types_str }
       }
       {
@@ -2457,13 +2559,13 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Set Environments and New Environments}
+%%> \section{Set Environments and New Environments}
 %%% --------------------------------------------------------
 
 \tl_new:N \l__tblr_initial_tblr_outer_tl
 \tl_set:Nn \l__tblr_initial_tblr_outer_tl
   {
-    halign = c, valign = m, headsep = 6pt, footsep = 6pt,
+    halign = c, baseline = m, headsep = 6pt, footsep = 6pt,
     presep = 1.5\bigskipamount, postsep = 1.5\bigskipamount,
   }
 
@@ -2485,13 +2587,13 @@
 %% #1: env name
 \NewDocumentCommand \NewTblrEnviron { m }
   {
-    \tl_new:c { l__tblr_default_ #1 _outer_tl }
-    \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl
-    \tl_new:c { l__tblr_default_ #1 _inner_tl }
     \NewDocumentEnvironment {#1} { O{c} m +b }
       {
         \__tblr_environ_code:nnnn {#1} {##1} {##2} {##3}
       } { }
+    \tl_new:c { l__tblr_default_ #1 _inner_tl }
+    \tl_new:c { l__tblr_default_ #1 _outer_tl }
+    \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl
     \ignorespaces
   }
 
@@ -2550,7 +2652,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Split Table Contents}
+%%> \section{Split Table Contents}
 %%% --------------------------------------------------------
 
 %% Insert and remove braces for nesting environments inside cells
@@ -2628,7 +2730,7 @@
       {
         \tl_if_head_eq_meaning:nNTF {##1} *
           {
-            \tl_set:Nn \l__tblr_b_tl { \SetRow { break = -1 } }
+            \tl_set:Nn \l__tblr_b_tl { \hborder { pagebreak = no } }
             \tl_set:Nx \l__tblr_c_tl { \tl_tail:n {##1} }
             \tl_trim_spaces:N \l__tblr_c_tl %% Ignore spaces between * and [dimen]
             \tl_if_head_eq_meaning:VNT \l__tblr_c_tl [
@@ -2681,7 +2783,6 @@
         \__tblr_extract_table_commands:N \l_tmpa_tl
         \__tblr_trim_par_space_tokens:N \l_tmpa_tl
         \__tblr_spec_gput:neV { text } { [#1][\int_use:N \c at colnum] } \l_tmpa_tl
-        \__tblr_add_multicolumn_empty_cell:
       }
     %% Decrease row count by 1 if the last row has only one empty cell text
     %% We need to do it here since the > or < column type may add text to cells
@@ -2711,26 +2812,12 @@
     \regex_replace_once:NnN \c__tblr_trim_right_space_par_regex {} #1
   }
 
-%% Add empty cells after the \multicolumn span cell
-\cs_new_protected:Npn \__tblr_add_multicolumn_empty_cell:
-  {
-    \int_step_inline:nn { \l__multicolumn_cell_number_int - 1 }
-      {
-        \int_incr:N \c at colnum
-        \__tblr_spec_gput:nen { text }
-          { [\int_use:N \c at rownum][\int_use:N \c at colnum] } { }
-      }
-  }
-
 %%% --------------------------------------------------------
-%%  \section{Extract Table Commands from Cell Text}
+%%> \section{Extract Table Commands from Cell Text}
 %%% --------------------------------------------------------
 
 %% Extract table commands defined with \NewTableCommand from cell text
 
-\clist_gset:Nn \g__tblr_table_commands_unbrace_next_clist {\multirow, \multicolumn}
-\bool_new:N \l__tblr_table_command_unbrace_next_bool
-\int_new:N \l__multicolumn_cell_number_int
 \tl_new:N \l__tblr_saved_table_commands_before_cell_text_tl
 \tl_new:N \l__tblr_saved_cell_text_after_table_commands_tl
 
@@ -2738,7 +2825,6 @@
   {
     \tl_clear:N \l__tblr_saved_table_commands_before_cell_text_tl
     \tl_clear:N \l__tblr_saved_cell_text_after_table_commands_tl
-    \int_set:Nn \l__multicolumn_cell_number_int {1}
     \exp_last_unbraced:NV \__tblr_extract_table_commands_next:n #1 \q_stop
     \tl_if_empty:NF \l__tblr_saved_table_commands_before_cell_text_tl
       {
@@ -2755,15 +2841,8 @@
     \tl_if_single_token:nTF {#1}
       {
         \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 }
+          { \__tblr_extract_one_table_command:N #1 }
           {
-            \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 }
-              { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool }
-              { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool }
-            \token_if_eq_meaning:NNTF #1 \multicolumn
-              { \__tblr_extract_multicolumn_command:Nn #1 }
-              { \__tblr_extract_one_table_command:N #1 }
-          }
-          {
             \token_if_eq_meaning:NNF #1 \q_stop
               { \__tblr_save_real_cell_text:w #1 }
           }
@@ -2771,12 +2850,6 @@
       { \__tblr_save_real_cell_text:w {#1} }
   }
 
-\cs_new_protected:Npn \__tblr_extract_multicolumn_command:Nn #1 #2
-  {
-    \int_set:Nn \l__multicolumn_cell_number_int {#2}
-    \__tblr_extract_one_table_command:N #1 {#2}
-  }
-
 \cs_new_protected:Npn \__tblr_extract_one_table_command:N #1
   {
     \int_set:Nn \l__tblr_a_int
@@ -2811,15 +2884,9 @@
         \int_decr:N \l__tblr_a_int
         \__tblr_extract_table_command_arg_m:n
       }
-      {
-        \bool_if:NTF \l__tblr_table_command_unbrace_next_bool
-          { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:n }
-          { \__tblr_extract_table_commands_next:n }
-      }
+      { \__tblr_extract_table_commands_next:n }
   }
 
-\cs_new_protected:Npn \__tblr_last_unbraced:Nn #1 #2 { #1 #2 }
-
 %% The outermost set of braces of cell text #1 will be removed
 \cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \q_stop
   {
@@ -2827,7 +2894,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Initialize Table Inner Specifications}
+%%> \section{Initialize Table Inner Specifications}
 %%% --------------------------------------------------------
 
 \prop_gset_from_keyval:Nn \g__tblr_initial_table_prop
@@ -2858,7 +2925,7 @@
 
 \prop_gset_from_keyval:Nn \g__tblr_initial_cells_prop
   {
-    halign = l,
+    halign = j,
     valign = t,
     width = -1pt, % cell width unset
     rowspan = 1,
@@ -2937,10 +3004,10 @@
 \clist_new:N \g__tblr_table_known_keys_clist
 \clist_gset:Nn \g__tblr_table_known_keys_clist
   {
-    colspec, rowspec, width, hspan, vspan, stretch, verb,
-    column, row, cell, vline, hline, columns, rows, cells, vlines, hlines,
+    colspec, rowspec, column, row, cell, hline, vline, hborder, vborder, width,
+    rowhead, rowfoot, columns, rows, cells, hlines, vlines, % hborders, vborders,
     leftsep, rightsep, colsep, abovesep, belowsep, rowsep, rulesep,
-    rowhead, rowfoot,
+    baseline, hspan, vspan, stretch, verb,
   }
 
 \keys_define:nn { tblr }
@@ -2967,6 +3034,7 @@
     rulesep .code:n = \__tblr_keys_gput:nn { rulesep } {#1},
     rowhead .code:n = \__tblr_keys_gput:nn { rowhead } {#1},
     rowfoot .code:n = \__tblr_keys_gput:nn { rowfoot } {#1},
+    baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1},
     unknown .code:n = \__tblr_table_special_key:Vn \l_keys_key_str {#1},
   }
 
@@ -3007,14 +3075,21 @@
 \cs_generate_variant:Nn \__tblr_keys_gput:nn { nx }
 
 %%% --------------------------------------------------------
-%%  \section{Initialize and Parse Table Outer Specifications}
+%%> \section{Initialize and Parse Table Outer Specifications}
 %%% --------------------------------------------------------
 
+\msg_new:nnn { tabularray } { used-theme-name }
+  { theme ~ name ~ #1 ~ has ~ been ~ used! }
+
 %% #1: theme names; #2: template and style commands
 \NewDocumentCommand \NewTblrTheme { m +m }
   {
-    \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2}
-    \ignorespaces
+    \tl_if_exist:cTF { g__tblr_theme_ #1 _code_tl }
+      { \msg_error:nnn { tabularray } { used-theme-name } { #1 } }
+      {
+        \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2}
+        \ignorespaces
+      }
   }
 
 \cs_new_protected:Npn \__tblr_use_theme:n #1
@@ -3038,13 +3113,17 @@
     long    .code:n = \__tblr_outer_gput_spec:nn { long } { true },
     tall    .code:n = \__tblr_outer_gput_spec:nn { tall } { true },
     halign  .code:n = \__tblr_outer_gput_spec:nn { halign } {#1},
-    valign  .code:n = \__tblr_outer_gput_spec:nn { valign } {#1},
+    baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1},
     l       .meta:n = { halign = l },
     c       .meta:n = { halign = c },
     r       .meta:n = { halign = r },
-    t       .meta:n = { valign = t },
-    m       .meta:n = { valign = m },
-    b       .meta:n = { valign = b },
+    t       .meta:n = { baseline = t },
+    T       .meta:n = { baseline = T },
+    m       .meta:n = { baseline = m },
+    M       .meta:n = { baseline = M },
+    b       .meta:n = { baseline = b },
+    B       .meta:n = { baseline = B },
+    valign  .meta:n = { baseline = #1 }, % obsolete, will be removed some day
     expand  .code:n = \__tblr_outer_gput_spec:nn { expand } {#1},
     headsep .code:n = \__tblr_outer_gput_spec:nn { headsep } {#1},
     footsep .code:n = \__tblr_outer_gput_spec:nn { footsep } {#1},
@@ -3061,6 +3140,7 @@
   {
     \__tblr_spec_gput:nen { outer } {#1} {#2}
   }
+\cs_generate_variant:Nn \__tblr_outer_gput_spec:nn { ne }
 
 \regex_const:Nn \c__tblr_option_key_name_regex { ^ [A-Za-z\-] + $ }
 
@@ -3102,7 +3182,7 @@
 \cs_generate_variant:Nn \__tblr_outer_gput_more:nn { Vn }
 
 %%% --------------------------------------------------------
-%%  \section{Typeset and Calculate Sizes}
+%%> \section{Typeset and Calculate Sizes}
 %%% --------------------------------------------------------
 
 %% Calculate the width and height for every cell and border
@@ -3125,12 +3205,47 @@
 \cs_new_protected:Npn \__tblr_make_strut_box:
   {
     \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { inner } { stretch } }
-    \hbox_set:Nn \l__tblr_strut_ht_box
-      { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt }
-    \hbox_set:Nn \l__tblr_strut_dp_box
-      { \vrule depth \l__tblr_s_tl \box_dp:N \strutbox width ~ 0pt }
+    \fp_compare:nNnTF { \l__tblr_s_tl } > {0}
+      {
+        \hbox_set:Nn \l__tblr_strut_ht_box
+          { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt }
+        \hbox_set:Nn \l__tblr_strut_dp_box
+          { \vrule depth \l__tblr_s_tl \box_dp:N \strutbox width ~ 0pt }
+        \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_real:
+        \cs_set_eq:NN \__tblr_use_strut_dp_box: \__tblr_use_strut_dp_box_real:
+      }
+      {
+        \fp_compare:nNnTF { \l__tblr_s_tl } < {0}
+          {
+            \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_vmode:
+          }
+          {
+            \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_hmode:
+          }
+        \cs_set_eq:NN \__tblr_use_strut_dp_box: \__tblr_use_strut_dp_box_ignore:
+      }
   }
 
+\cs_new_protected:Npn \__tblr_use_strut_ht_box_real:
+  {
+    \mode_leave_vertical:
+    \box_use:N \l__tblr_strut_ht_box
+  }
+\cs_new_protected:Npn \__tblr_use_strut_ht_box_hmode:
+  {
+    \mode_leave_vertical:
+  }
+\cs_new_protected:Npn \__tblr_use_strut_ht_box_vmode:
+  {
+    \@minipagetrue % for lists (see issue #99)
+  }
+
+\cs_new_protected:Npn \__tblr_use_strut_dp_box_real:
+  {
+    \box_use:N \l__tblr_strut_dp_box
+  }
+\cs_new_protected:Npn \__tblr_use_strut_dp_box_ignore: { }
+
 %% Calculate the thickness for every hline and vline
 \cs_new_protected:Npn \__tblr_calculate_line_sizes:
   {
@@ -3207,7 +3322,11 @@
       {
         %% When using text as vline, we need to omit abovepos and belowpos.
         \unskip
-        \hbox_set:Nn \l__tblr_d_box { \l__tblr_b_tl }
+        \hbox_set:Nn \l__tblr_d_box
+          {
+            \bool_if:NTF \l__tblr_math_mode_bool
+              { $ \l__tblr_b_tl $ } { \l__tblr_b_tl }
+          }
         \box_set_ht:Nn \l__tblr_d_box {#4}
         \box_set_dp:Nn \l__tblr_d_box {#5}
         \box_use:N \l__tblr_d_box
@@ -3265,7 +3384,11 @@
         \__tblr_get_hline_dash_style:N \l__tblr_b_tl
         \xleaders \l__tblr_b_tl \hfil
       }
-      { \l__tblr_b_tl \hfil }
+      {
+        \bool_if:NTF \l__tblr_math_mode_bool
+          { $ \l__tblr_b_tl $ } { \l__tblr_b_tl }
+        \hfil
+      }
     \group_end:
   }
 
@@ -3329,6 +3452,7 @@
     %% You can use these two counters in cell text
     \int_zero:N \c at rownum
     \int_zero:N \c at colnum
+    \__tblr_save_counters:n { table }
     \int_step_inline:nn { \c at rowcount }
       {
         \int_incr:N \c at rownum
@@ -3355,6 +3479,7 @@
               \g__tblr_cell_foot_dim
           }
       }
+    \__tblr_restore_counters:n { table }
     \int_step_inline:nn { \c at colcount }
       {
         \tl_set:Nx \l__tblr_w_tl
@@ -3388,9 +3513,7 @@
 \cs_new_protected:Npn \__tblr_measure_cell_update_sizes:nnNNNN #1 #2 #3 #4 #5 #6
   {
     \__tblr_get_cell_alignments:nn {#1} {#2}
-    \__tblr_save_counters:n { trial }
     \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} }
-    \__tblr_restore_counters:n { trial }
     \__tblr_update_cell_size:nnNNNN {#1} {#2} #3 #4 #5 #6
     \__tblr_update_row_size:nnNNN {#1} {#2} #4 #5 #6
     \__tblr_update_col_size:nN {#2} #3
@@ -3423,13 +3546,21 @@
 \cs_new_protected:Npn \__tblr_get_cell_text_real:nn #1 #2
   {
     \group_begin:
-    \tl_set:Nx \l__tblr_cell_cmd_tl
-      { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } }
-    \tl_if_empty:NTF \l__tblr_cell_cmd_tl
-      { \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} } }
+    \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} }
+    %% when the cell text is guarded by a pair of curly braces,
+    %% we unbrace it and ignore cmd option of the cell, see issue #90.
+    \bool_lazy_and:nnTF
+      { \tl_if_single_p:N \l__tblr_c_tl }
+      { \exp_args:NV \tl_if_head_is_group_p:n \l__tblr_c_tl }
+      { \exp_last_unbraced:NNV \tl_set:Nn \l__tblr_c_tl \l__tblr_c_tl }
       {
-        \tl_set:Nx \l__tblr_c_tl { { \__tblr_spec_item:ne { text } {[#1][#2]} } }
-        \tl_put_left:NV \l__tblr_c_tl \l__tblr_cell_cmd_tl
+        \tl_set:Nx \l__tblr_cell_cmd_tl
+          { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } }
+        \tl_if_empty:NF \l__tblr_cell_cmd_tl
+          {
+            \tl_set:Nx \l__tblr_c_tl
+              { \exp_not:V \l__tblr_cell_cmd_tl { \exp_not:V \l__tblr_c_tl } }
+          }
       }
     \tl_set:Nx \l__tblr_cell_mode_tl
       { \__tblr_data_item:neen { cell } {#1} {#2} { mode } }
@@ -3462,14 +3593,17 @@
       }
     \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % column width unset
       {
+        \__tblr_save_counters:n { cell }
         \bool_if:NTF \l__tblr_cell_math_mode_bool
           {
-            \hbox_set:Nn \l_tmpa_box { \l__tblr_c_tl }
+            %% Note that font = \boldmath will increase cell width (issue #137)
+            \hbox_set:Nn \l_tmpa_box { \l__tblr_f_tl \l__tblr_c_tl }
             \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
           }
           {
             \__tblr_get_cell_size_with_box:
           }
+        \__tblr_restore_counters:n { cell }
       }
     \tl_set:Nx \l__tblr_cell_fg_tl
       { \__tblr_data_item:neen { cell } {#1} {#2} { foreground } }
@@ -3480,11 +3614,9 @@
 
 \cs_new_protected:Npn \__tblr_get_cell_size_with_box:
   {
-    \__tblr_save_counters:n { cell }
     \tl_if_eq:NnTF \l__tblr_inner_spec_measure_tl { vbox }
       { \__tblr_get_cell_size_with_vbox: }
       { \__tblr_get_cell_size_with_hbox: }
-    \__tblr_restore_counters:n { cell }
   }
 
 %% Varwidth won't work as expected when \color command occurs in it,
@@ -3494,6 +3626,9 @@
 %% or users may use it in the middle of the cell text,
 %% so we have redefine \color command and disable it before measuring cell.
 
+%% In order to correctly measure an enumerate environment,
+%% we need to enclose varwidth with NoHyper environment (see issue #196).
+
 \NewDocumentCommand \__tblr_fake_color_command:w { o m } { }
 
 \cs_new_protected:Npn \__tblr_get_cell_size_with_vbox:
@@ -3501,10 +3636,12 @@
     \hbox_set:Nn \l_tmpa_box
       {
         \cs_set_eq:NN \color \__tblr_fake_color_command:w
+        \begin{tblrNoHyper}
         \begin{varwidth}{\paperwidth}
            \l__tblr_f_tl
            \__tblr_rescan_cell_tokens:N \l__tblr_c_tl
         \end{varwidth}
+        \end{tblrNoHyper}
       }
     \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
   }
@@ -3582,15 +3719,15 @@
 \cs_new_protected:Npn \__tblr_make_vcell_text:NN #1 #2
   {
     \dim_set:Nn \tex_hsize:D { #2 }
-    \@arrayparboxrestore
+    \TblrParboxRestore
     \cs:w __tblr_halign_command_ \g__tblr_cell_halign_tl : \cs_end:
-    \mode_leave_vertical:
-    \box_use:N \l__tblr_strut_ht_box
+    %% \mode_leave_vertical: has been moved into \__tblr_use_strut_ht_box:
+    \__tblr_use_strut_ht_box:
     \tl_if_empty:NF \l__tblr_cell_fg_tl { \exp_args:NV \color \l__tblr_cell_fg_tl }
     \bool_if:NTF \l__tblr_cell_math_mode_bool
       { #1 }
       { \__tblr_rescan_cell_tokens:N #1 }
-    \box_use:N \l__tblr_strut_dp_box
+    \__tblr_use_strut_dp_box:
   }
 
 %% When using verb option, there is an end-of-line character at the end.
@@ -3775,7 +3912,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Calculate and Adjust Extendable Columns}
+%%> \section{Calculate and Adjust Extendable Columns}
 %%% --------------------------------------------------------
 
 %% Compute column widths when there are some extendable columns
@@ -3943,7 +4080,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Calculate and Adjust Multispan Cells}
+%%> \section{Calculate and Adjust Multispan Cells}
 %%% --------------------------------------------------------
 
 %% Compute and adjust widths when there are some span cells.
@@ -4479,6 +4616,7 @@
     \keys_set:nn { tblr-def-template } {#1}
     \ignorespaces
   }
+\cs_new_eq:NN \DeclareTblrTemplate \DefTblrTemplate
 
 \cs_new_protected:Npn \__tblr_def_template:n #1
   {
@@ -4869,11 +5007,16 @@
   }
 \SetTblrTemplate { note-border } { empty }
 
+\cs_set_eq:NN \TblrOverlap \rlap
+
 \NewDocumentCommand \TblrNote { m }
   {
     \cs_if_exist:NT \hypersetup { \ExpTblrTemplate { note-border }{ default } }
-    \__tblr_hyper_link:nn {#1}
-      { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } }
+    \TblrOverlap
+      {
+        \__tblr_hyper_link:nn {#1}
+          { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } }
+      }
   }
 
 \DefTblrTemplate { note-tag } { empty } { }
@@ -5146,16 +5289,26 @@
         \__tblr_build_table_label_entry:
         \UseTblrTemplate { firsthead } { default }
       }
-    \__tblr_build_table_head_aux:Nn
-      \l__tblr_table_middlehead_box { \UseTblrTemplate { middlehead } { default } }
-    \__tblr_build_table_head_aux:Nn
-      \l__tblr_table_lasthead_box  { \UseTblrTemplate { lasthead } { default } }
-    \__tblr_build_table_foot_aux:Nn
-      \l__tblr_table_firstfoot_box { \UseTblrTemplate { firstfoot } { default } }
-    \__tblr_build_table_foot_aux:Nn
-      \l__tblr_table_middlefoot_box { \UseTblrTemplate { middlefoot } { default } }
-    \__tblr_build_table_foot_aux:Nn
-      \l__tblr_table_lastfoot_box  { \UseTblrTemplate { lastfoot } { default } }
+    \__tblr_build_table_head_aux:Nn \l__tblr_table_middlehead_box
+      {
+        \UseTblrTemplate { middlehead } { default }
+      }
+    \__tblr_build_table_head_aux:Nn \l__tblr_table_lasthead_box
+      {
+        \UseTblrTemplate { lasthead } { default }
+      }
+    \__tblr_build_table_foot_aux:Nn \l__tblr_table_firstfoot_box
+      {
+        \UseTblrTemplate { firstfoot } { default }
+      }
+    \__tblr_build_table_foot_aux:Nn \l__tblr_table_middlefoot_box
+      {
+        \UseTblrTemplate { middlefoot } { default }
+      }
+    \__tblr_build_table_foot_aux:Nn \l__tblr_table_lastfoot_box
+      {
+        \UseTblrTemplate { lastfoot } { default }
+      }
   }
 
 \cs_new_protected:Npn \__tblr_build_tall_table_head_foot:
@@ -5192,9 +5345,12 @@
     \vbox_set:Nn #1
       {
         \hsize = \tablewidth
-        \parindent = 0pt \relax
-        \vbox:n {#2}
-        \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } }
+        \TblrParboxRestore % it will set \linewidth = \hsize
+        \vbox_set:Nn \l_tmpa_box {#2}
+        \box_use:N \l_tmpa_box
+        \dim_compare:nNnT
+          { \box_ht:N \l_tmpa_box + \box_dp:N \l_tmpa_box } > { 0pt }
+          { \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } } }
       }
   }
 
@@ -5203,9 +5359,12 @@
     \vbox_set:Nn #1
       {
         \hsize = \tablewidth
-        \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } }
-        \parindent = 0pt \relax
-        \vbox:n {#2}
+        \TblrParboxRestore % it will set \linewidth = \hsize
+        \vbox_set:Nn \l_tmpb_box {#2}
+        \dim_compare:nNnT
+          { \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box } > { 0pt }
+          { \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } } }
+        \box_use:N \l_tmpb_box
       }
   }
 
@@ -5217,11 +5376,11 @@
         \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { tall } } { true }
           {
             \__tblr_build_tall_table:e
-              { \__tblr_spec_item:nn { outer } { valign } }
+              { \__tblr_spec_item:nn { outer } { baseline } }
           }
           {
             \__tblr_build_short_table:e
-              { \__tblr_spec_item:nn { outer } { valign } }
+              { \__tblr_spec_item:nn { outer } { baseline } }
           }
       }
   }
@@ -5288,7 +5447,7 @@
                 \int_incr:N \l__tblr_table_page_int
                 \int_set:Nn \l__tblr_long_from_int { \l__tblr_prev_i_int + 1 }
               }
-            \newpage
+            \TblrNewPage
             \hbox{}\kern-\topskip\nobreak
             \noindent
             \LogTblrTracing { page }
@@ -5302,7 +5461,7 @@
                   { \int_use:N \l__tblr_long_from_int }
                   { \int_use:N \l__tblr_curr_i_int }
                 \int_incr:N \l__tblr_table_page_int
-                \newpage
+                \TblrNewPage
                 \hbox{}\kern-\topskip\nobreak
                 \noindent
                 \LogTblrTracing { page }
@@ -5356,12 +5515,17 @@
         \int_compare:nNnTF {#2} < {#1}
           {
             \tl_set:Nx \l__tblr_b_tl
-              { \__tblr_data_item:nen { row } { \int_eval:n { #2 + 1 } } { break } }
-            \int_compare:nNnTF { \l__tblr_b_tl } < { 0 }
+              {
+                \__tblr_spec_item:ne { hline }
+                  { [ \int_eval:n { #2 + 1 } ] / @pagebreak }
+              }
+            % Note that \l__tblr_b_tl may be empty
+            \int_compare:nNnTF { \l__tblr_b_tl + 0 } < { 0 }
               { \bool_set_true:N \l_tmpa_bool }
               {
                 \bool_set_false:N \l_tmpa_bool
-                \int_compare:nNnT { \l__tblr_b_tl } > { 0 } { \bool_set_true:N #4 }
+                \int_compare:nNnT { \l__tblr_b_tl + 0 } > { 0 }
+                  { \bool_set_true:N #4 }
               }
           }
           { \bool_set_false:N \l_tmpa_bool }
@@ -5425,7 +5589,7 @@
         \hrule height ~ 0pt
         \box_use:N \l__tblr_table_foot_box
       }
-    \__tblr_halign_whole:Nn \l__tblr_table_box #1
+    \__tblr_halign_whole:Nn \l__tblr_table_box {#1}
   }
 \cs_generate_variant:Nn \__tblr_build_page_table:nnn { nnx }
 
@@ -5463,7 +5627,6 @@
 \cs_new_protected:Npn \__tblr_build_tall_table:n #1
   {
     \mode_leave_vertical:
-    \raggedright
     \__tblr_build_tall_table_head_foot:
     \__tblr_build_one_table:nn {1} {\c at rowcount}
     \vbox_set:Nn \l__tblr_table_box
@@ -5474,7 +5637,7 @@
         \hrule height ~ 0pt
         \box_use:N \l__tblr_table_lastfoot_box
       }
-    \__tblr_valign_whole:Nn \l__tblr_table_box #1
+    \__tblr_valign_whole:Nn \l__tblr_table_box {#1}
   }
 \cs_generate_variant:Nn \__tblr_build_tall_table:n { e }
 
@@ -5484,7 +5647,7 @@
   {
     \mode_leave_vertical:
     \__tblr_build_one_table:nn {1} {\c at rowcount}
-    \__tblr_valign_whole:Nn \l__tblr_table_box #1
+    \__tblr_valign_whole:Nn \l__tblr_table_box {#1}
   }
 \cs_generate_variant:Nn \__tblr_build_short_table:n { e }
 
@@ -5561,10 +5724,16 @@
 
 \tl_new:N \__tblr_vbox_align_tl
 \tl_const:Nn \__tblr_vbox_t_tl {t}
+\tl_const:Nn \__tblr_vbox_T_tl {T}
 \tl_const:Nn \__tblr_vbox_m_tl {m}
+\tl_const:Nn \__tblr_vbox_M_tl {M}
 \tl_const:Nn \__tblr_vbox_c_tl {c}
 \tl_const:Nn \__tblr_vbox_b_tl {b}
+\tl_const:Nn \__tblr_vbox_B_tl {B}
 
+\regex_const:Nn \c__tblr_is_positive_integer_regex { ^ \d+ $ }
+\regex_const:Nn \c__tblr_is_negative_integer_regex { ^ - \d+ $ }
+
 \cs_new_protected:Npn \__tblr_valign_whole:Nn #1 #2
   {
     \group_begin:
@@ -5576,12 +5745,34 @@
           { \__tblr_valign_whole_middle:N #1 }
         \__tblr_vbox_c_tl
           { \__tblr_valign_whole_middle:N #1 }
+        \__tblr_vbox_M_tl
+          { \__tblr_valign_whole_middle_row_or_border:N #1 }
         \__tblr_vbox_t_tl
           { \__tblr_valign_whole_top:N #1 }
+        \__tblr_vbox_T_tl
+          {
+            \tl_set:Nn \__tblr_vbox_align_tl {1}
+            \__tblr_valign_whole_at_row_from_above:N #1
+          }
         \__tblr_vbox_b_tl
           { \__tblr_valign_whole_bottom:N #1 }
+        \__tblr_vbox_B_tl
+          {
+            \tl_set:Nx \__tblr_vbox_align_tl { \int_use:N \c at rowcount }
+            \__tblr_valign_whole_at_row_from_below:N #1
+          }
       }
-      { \__tblr_valign_whole_middle:N #1 }
+      {
+        \regex_match:NVTF \c__tblr_is_positive_integer_regex \__tblr_vbox_align_tl
+          { \__tblr_valign_whole_at_row:N #1 }
+          {
+            \regex_match:NVTF
+              \c__tblr_is_negative_integer_regex \__tblr_vbox_align_tl
+              { \__tblr_valign_whole_at_border:N #1 }
+              { \__tblr_valign_whole_middle:N #1 }
+          }
+      }
+    \box_use_drop:N #1
     \group_end:
   }
 
@@ -5592,76 +5783,149 @@
 
 \cs_new_protected:Npn \__tblr_valign_whole_top:N #1
   {
-    \tl_set:Nx \l__tblr_a_tl
-      { \__tblr_spec_item:ne { hline } { [1] / @hline-height } }
-    %% Note that \l__tblr_b_tl may be empty
-    \tl_set:Nx \l__tblr_b_tl
-      { \__tblr_prop_item:ne { inner } { baseline } }
-    \bool_lazy_or:nnTF
-      { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } }
-      { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { 1 } }
+    \dim_set:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {1} }
+    \dim_compare:nNnT \l__tblr_h_dim = { 0pt }
+      { \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_height:n {1} } }
+    \box_set_ht:Nn #1 { \l__tblr_h_dim }
+    \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_bottom:N #1
+  {
+    \dim_set:Nn \l__tblr_d_dim
+      { \__tblr_valign_get_hline_total:n { \int_eval:n { \c at rowcount + 1 } } }
+    \dim_compare:nNnTF \l__tblr_d_dim = { 0pt }
       {
-        \dim_set:Nn \l__tblr_h_dim
-          {
-            \__tblr_data_item:nnn { row } {1} { abovesep }
-            +
-            ( \__tblr_data_item:nnn { row } {1} { @row-height }
-              +
-              \__tblr_data_item:nnn { row } {1} { @row-upper }
-              -
-              \__tblr_data_item:nnn { row } {1} { @row-lower }
-            ) / 2
-          }
-        \dim_set:Nn \l__tblr_d_dim { \l__tblr_t_dim - \l__tblr_h_dim }
+        \dim_set:Nn \l__tblr_d_dim
+          { \__tblr_valign_get_row_depth:n { \int_use:N \c at rowcount } }
       }
+      { \dim_zero:N \l__tblr_d_dim }
+    \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
+    \box_set_dp:Nn #1 { \l__tblr_d_dim }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_middle_row_or_border:N #1
+  {
+    \int_if_odd:nTF { \c at rowcount }
       {
-        \dim_set:Nn \l__tblr_h_dim { 0pt }
-        \dim_set_eq:NN \l__tblr_d_dim \l__tblr_t_dim
+        \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { (\c at rowcount + 1) / 2 } }
+        \__tblr_valign_whole_at_row_from_above:N #1
       }
+      {
+        \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { \c at rowcount / 2 + 1 } }
+        \__tblr_valign_whole_at_border_from_above:N #1
+      }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_at_row:N #1
+  {
+    \int_compare:nNnTF { 2 * \__tblr_vbox_align_tl } > { \c at rowcount }
+      { \__tblr_valign_whole_at_row_from_below:N #1 }
+      { \__tblr_valign_whole_at_row_from_above:N #1 }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_above:N #1
+  {
+    \dim_set:Nn \l__tblr_h_dim
+      { \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } }
+    \dim_add:Nn \l__tblr_h_dim
+      { \__tblr_valign_get_row_height:n { \__tblr_vbox_align_tl } }
+    \int_step_inline:nn { \__tblr_vbox_align_tl - 1 }
+      {
+        \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} }
+        \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} }
+      }
     \box_set_ht:Nn #1 { \l__tblr_h_dim }
-    \box_set_dp:Nn #1 { \l__tblr_d_dim }
-    \box_use_drop:N #1
+    \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
   }
 
-\cs_new_protected:Npn \__tblr_valign_whole_bottom:N #1
+\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_below:N #1
   {
-    \tl_set:Nx \l__tblr_a_tl
+    \dim_set:Nn \l__tblr_d_dim
+      { \__tblr_valign_get_hline_total:n { \int_eval:n {\c at rowcount + 1} } }
+    \dim_add:Nn \l__tblr_d_dim
+      { \__tblr_valign_get_row_depth:n { \__tblr_vbox_align_tl } }
+    \int_step_inline:nnn { \__tblr_vbox_align_tl + 1 } { \c at rowcount }
       {
-        \__tblr_spec_item:ne { hline }
-          { [\int_eval:n {\c at rowcount + 1}] / @hline-height }
+        \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_hline_total:n {##1} }
+        \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} }
       }
-    %% Note that \l__tblr_b_tl may be empty
-    \tl_set:Nx \l__tblr_b_tl
-      { \__tblr_prop_item:ne { inner } { baseline } }
-    \bool_lazy_or:nnTF
-      { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } }
-      { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { \c at rowcount } }
+    \box_set_dp:Nn #1 { \l__tblr_d_dim }
+    \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_at_border:N #1
+  {
+    \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { - \__tblr_vbox_align_tl } }
+    \int_compare:nNnTF { 2 * \__tblr_vbox_align_tl - 2 } > { \c at rowcount }
+      { \__tblr_valign_whole_at_border_from_below:N #1 }
+      { \__tblr_valign_whole_at_border_from_above:N #1 }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_above:N #1
+  {
+    \dim_set:Nn \l__tblr_h_dim
+      { \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } }
+    \int_step_inline:nn { \__tblr_vbox_align_tl - 1 }
       {
-        \dim_set:Nn \l__tblr_d_dim
-          {
-            ( \__tblr_data_item:nen { row }
-                { \int_use:N \c at rowcount } { @row-height }
-              -
-              \__tblr_data_item:nen { row }
-                { \int_use:N \c at rowcount } { @row-upper }
-              +
-              \__tblr_data_item:nen { row }
-                { \int_use:N \c at rowcount } { @row-lower }
-            ) / 2
-            +
-            \__tblr_data_item:nnn { row } {1} { belowsep }
-          }
-        \dim_set:Nn \l__tblr_h_dim { \l__tblr_t_dim - \l__tblr_d_dim }
+        \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} }
+        \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} }
       }
+    \box_set_ht:Nn #1 { \l__tblr_h_dim }
+    \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
+  }
+
+\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_below:N #1
+  {
+    \dim_zero:N \l__tblr_d_dim
+    \int_step_inline:nnn { \__tblr_vbox_align_tl } { \c at rowcount }
       {
-        \dim_set:Nn \l__tblr_d_dim { 0pt }
-        \dim_set_eq:NN \l__tblr_h_dim \l__tblr_t_dim
+        \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} }
+        \dim_add:Nn \l__tblr_d_dim
+          { \__tblr_valign_get_hline_total:n { \int_eval:n { ##1 + 1 } } }
       }
-    \box_set_ht:Nn #1 { \l__tblr_h_dim }
     \box_set_dp:Nn #1 { \l__tblr_d_dim }
-    \box_use_drop:N #1
+    \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
   }
 
+\cs_new_nopar:Npn \__tblr_valign_get_hline_total:n #1
+  {
+    \__tblr_spec_item:ne { hline } { [#1] / @hline-height }
+  }
+
+\cs_new_nopar:Npn \__tblr_valign_get_row_total:n #1
+  {
+    \__tblr_data_item:nnn { row } {#1} { abovesep }
+    +
+    \__tblr_data_item:nnn { row } {#1} { @row-height }
+    +
+    \__tblr_data_item:nnn { row } {#1} { belowsep }
+  }
+
+\cs_new_nopar:Npn \__tblr_valign_get_row_height:n #1
+  {
+    \__tblr_data_item:nnn { row } {#1} { abovesep }
+    +
+    ( \__tblr_data_item:nnn { row } {#1} { @row-height }
+      +
+      \__tblr_data_item:nnn { row } {#1} { @row-upper }
+      -
+      \__tblr_data_item:nnn { row } {#1} { @row-lower }
+    ) / 2
+  }
+
+\cs_new_nopar:Npn \__tblr_valign_get_row_depth:n #1
+  {
+    ( \__tblr_data_item:nen { row } {#1} { @row-height }
+      -
+      \__tblr_data_item:nen { row } {#1} { @row-upper }
+      +
+      \__tblr_data_item:nen { row } {#1} { @row-lower }
+    ) / 2
+    +
+    \__tblr_data_item:nnn { row } {#1} { belowsep }
+  }
+
 %%% --------------------------------------------------------
 %%> \section{Build Table Components}
 %%% --------------------------------------------------------
@@ -6064,7 +6328,8 @@
     \hbox_set_to_wd:Nnn \l__tblr_a_box { \l__tblr_cell_wd_dim }
       {
         \tl_if_eq:NnTF \g__tblr_cell_halign_tl {j}
-          { \__tblr_get_cell_text:nn {#1} {#2} }
+          % cell width may be less than column width for j cells
+          { \__tblr_get_cell_text:nn {#1} {#2} \hfil }
           {
             \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil }
             \__tblr_get_cell_text:nn {#1} {#2}
@@ -6245,14 +6510,13 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Tracing Tabularray}
+%%> \section{Tracing Tabularray}
 %%% --------------------------------------------------------
 
-\NewDocumentCommand \SetTabularrayTracing { m }
+\NewDocumentCommand \SetTblrTracing { m }
   {
     \keys_set:nn { tblr-set-tracing } {#1}
   }
-\cs_new_eq:NN \SetTblrTracing \SetTabularrayTracing
 
 \bool_new:N \g__tblr_tracing_text_bool
 \bool_new:N \g__tblr_tracing_command_bool
@@ -6361,11 +6625,10 @@
     \bool_gset_false:N \g__tblr_tracing_step_bool
   }
 
-\NewDocumentCommand \LogTabularrayTracing { m }
+\NewDocumentCommand \LogTblrTracing { m }
   {
     \keys_set:nn { tblr-log-tracing } {#1}
   }
-\cs_new_eq:NN \LogTblrTracing \LogTabularrayTracing
 
 \keys_define:nn { tblr-log-tracing }
   {
@@ -6482,7 +6745,7 @@
   }
 
 %%% --------------------------------------------------------
-%%  \section{Tabularray Libraries}
+%%> \section{Tabularray Libraries}
 %%% --------------------------------------------------------
 
 %% \NewTblrLibrary and \UseTblrLibrary commands
@@ -6571,17 +6834,18 @@
     \RequirePackage { booktabs }
     \newcommand \tblr at booktabs@hline [1] [] { \hline [##1] }
     \newcommand \tblr at booktabs@oldhline [1] [] {
-      \hline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1]
+      \hline [##1]
+      \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
     }
     \newcommand \tblr at booktabs@cline [2] [] { \cline [##1] {##2} }
     \newcommand \tblr at booktabs@oldcline [2] [] {
-      \cline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] {##2}
+      \cline [##1] {##2}
+      \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
     }
     \newcommand \tblr at booktabs@cline at more [2] [] { \SetHline [+] {##2} {##1} }
     \newcommand \tblr at booktabs@oldcline at more [2] [] {
-      \SetHline [+] {##2} {
-        abovespace = \aboverulesep, belowspace = \belowrulesep, ##1
-      }
+      \SetHline [+] {##2} {##1}
+      \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
     }
     \NewTableCommand \toprule [1] [] {
       \tblr at booktabs@hline [wd=\heavyrulewidth, ##1]
@@ -6603,20 +6867,29 @@
       \peek_meaning:NTF \cmidrule { \tblr at booktabs@change at more } { \relax }
     }
     \NewTblrEnviron { booktabs }
+    \NewTblrEnviron { longtabs }
+    \NewTblrEnviron { talltabs }
     \SetTblrInner [ booktabs ] { rowsep = 0pt }
+    \SetTblrInner [ longtabs ] { rowsep = 0pt }
+    \SetTblrInner [ talltabs ] { rowsep = 0pt }
+    \SetTblrOuter [ longtabs ] { long }
+    \SetTblrOuter [ talltabs ] { tall }
     \RequirePackage { etoolbox }
-    \AtBeginEnvironment { booktabs }
+    \newcommand \tblr at booktabs@begin at hook
       {
         \let \tblr at booktabs@hline = \tblr at booktabs@oldhline
         \let \tblr at booktabs@cline = \tblr at booktabs@oldcline
         \let \tblr at booktabs@cline at more = \tblr at booktabs@oldcline at more
       }
+    \AtBeginEnvironment { booktabs } { \tblr at booktabs@begin at hook }
+    \AtBeginEnvironment { longtabs } { \tblr at booktabs@begin at hook }
+    \AtBeginEnvironment { talltabs } { \tblr at booktabs@begin at hook }
     \NewTableCommand \specialrule [3]
-      { \hline [##1, abovespace = ##2, belowspace = ##3] }
+      { \hline [##1] \hborder { abovespace = ##2, belowspace = ##3 } }
     \NewTableCommand \addrowspace [1] [\defaultaddspace]
-      { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
+      { \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
     \NewTableCommand \addlinespace [1] [\defaultaddspace]
-      { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
+      { \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
   }
 
 %% Library counter for resetting all counters



More information about the tex-live-commits mailing list.