How to overbrace / underbrace in text mode (using TikZ?)

Using a matrix of nodes and then making use of the corners of those nodes (via .north west, .north east, .south west, and .south east) for \drawing the paths, combined with the ability to set nodes along paths, allows you to do this in TikZ. Moreover, you can use \tikzstyle to set some of the options globally, so you don't have to manually adjust the position of the labels continually:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{decorations.pathreplacing}

\tikzstyle{overbrace text style}=[font=\tiny, above, pos=.5, yshift=3mm]
\tikzstyle{overbrace style}=[decorate,decoration={brace,raise=2mm,amplitude=3pt}]
\tikzstyle{underbrace style}=[decorate,decoration={brace,raise=2mm,amplitude=3pt,mirror},color=gray]
\tikzstyle{underbrace text style}=[font=\tiny, below, pos=.5, yshift=-3mm]

\begin{document}

\begin{tikzpicture}

    \matrix[name=M1, matrix of nodes, inner sep=0pt, column sep=0pt]{
      \node (schema) [text=red] {http:\vphantom{/}}; & \node (schema-spezifisch) [text=black] {//}; & \node (nutzerinfo) [text=orange] {user:pass\vphantom{/}}; & @ & \node (host) [text=blue] {www.example.com\vphantom{/}}; & : & \node (port) [text=blue!40] {1234\vphantom{/}}; & \node (pfad) [text=red] {/directory/index.php}; & \node (query) [text=purple] {?key=value\vphantom{/}}; & \node (fragment) [text=green] {\#anchor\vphantom{/}};  \\
    };

    \draw [overbrace style] (schema.north west) -- (schema.north east) node [overbrace text style] {Schema};
    \draw [overbrace style] (schema-spezifisch.north west) -- (fragment.north east) node [overbrace text style] {Schema-Spezifisch};
    \draw [underbrace style] (nutzerinfo.south west) -- (nutzerinfo.south east) node [underbrace text style,text=orange] {Nutzerinfo};
    \draw [underbrace style] (host.south west) -- (host.south east) node [underbrace text style,text=blue] {Host};
    \draw [underbrace style] (port.south west) -- (port.south east) node [underbrace text style,text=blue!40,baseline] {Port};
    \draw [underbrace style] (pfad.south west) -- (pfad.south east) node [underbrace text style,text=red] {Pfad};
    \draw [underbrace style] (query.south west) -- (query.south east) node [underbrace text style,text=purple] {Query};
    \draw [underbrace style] (fragment.south west) -- (fragment.south east) node [underbrace text style,text=green] {Fragment};

\end{tikzpicture}

\begin{tikzpicture}

    \matrix[name=M2, matrix of nodes, inner sep=0pt, column sep=0pt]{
      \node (URI) {http:}; & \node (schema) [text=black] {//user:[email protected]:port/resource?query=foo}; & \node (fragment) {\#fragment};  \\
    };

    \draw [overbrace style] (URI.north west) -- (fragment.north east) node [overbrace text style] {URI};
    \draw [decorate,decoration={brace,raise=6mm,amplitude=3pt,mirror},color=gray] (schema.south west) -- (fragment.south east) node [font=\tiny, below, pos=.5, yshift=-7mm] {Schema};
    \draw [underbrace style] (fragment.south west) -- (fragment.south east) node [underbrace text style] {Fragment};

\end{tikzpicture}

\end{document}

enter image description here

You will just have to make sure that each place where you need to place the beginning or ending of an underbrace or overbrace is set as its own node in its own column of the matrix.

Moreover, if you don't want to have to set the options manually for the lower underbrace in the second tikzpicture, you could set something like an 'under-underbrace \tikzstyle' globally, or something like that.


Additionally, you could also wrap the \draw commands in a macro. For example, you could put this in the preamble:

\usepackage{twoopt}
\newcommandtwoopt{\tikzoverbrace}[5][][]{\draw [overbrace style,#1] (#3.north west) -- (#4.north east) node [overbrace text style,#2] {#5};}
\newcommandtwoopt{\tikzunderbrace}[5][][]{\draw [underbrace style,#1] (#3.south west) -- (#4.south east) node [underbrace text style,#2] {#5};}

And then you could write:

\tikzoverbrace{schema-spezifisch}{fragment}{Schema-Spezifisch}

instead of:

\draw [overbrace style] (schema-spezifisch.north west) -- (fragment.north east) node [overbrace text style] {Schema-Spezifisch};

And you could also write:

\tikzunderbrace[][text=orange]{nutzerinfo}{nutzerinfo}{Nutzerinfo}

instead of:

\draw [underbrace style] (nutzerinfo.south west) -- (nutzerinfo.south east) node [underbrace text style,text=orange] {Nutzerinfo};

You'll still have to set the matrix independently of these new commands, with this solution, however.


Update:

As @FrederickNord points out in the comments, adding nodes={anchor=south}, text height=1.5ex,text depth=.25ex to the matrix style will ensure that the overbraces and underbraces (at least in this particular MWE) are correctly aligned. Another option is to use \vphantom{...} inside the nodes, which is the option used in the MWE above.


A simple solution I used when I needed to underbrace text was simple to use math mode wrapped inside a new command:

\newcommand{\undertext}[2] {$\underbrace{\textrm{#1}}_{\textrm{#2}}$}

Then you just \undertext{any text}{like this}

Tags:

Tikz Pgf