hyperref targets without \refstepcounter

I am trying to create a document-internal link using the hyperref package. At the position where the link should point to, I execute the following command (as part of the setup of a LaTeX environment):

\edef\@currentlabel{LABEL}


After this, I use \label{...} to create a reference and the \ref{...}. The hyperref package turns the \ref{...} into a hyperlink as expected, but the link points to the wrong location (further up in the text). How do I tell hyperref where the link should point to?

I cannot use \refstepcounter because my labels are textual and not associated to a LaTeX counter.

Here is a "minimal" (well, "smallish") working example to illustrate the problem:

\documentclass{article}

\usepackage{lipsum}
\usepackage{amsthm}
\usepackage{hyperref}

\newtheorem{theorem}{Theorem}[section]

\makeatletter
\newenvironment{algorithm}[2]%
{\medbreak
\edef\@currentlabel{#1}%
% more stuff here (put entry in table of algorithms, etc.)
\noindent
\textbf{Algorithm~\@currentlabel\ (#2)}\hfill\break
\ignorespaces}%
{\medbreak}
\makeatother

\begin{document}

\section{Test}

\begin{theorem}
\lipsum[1]
\end{theorem}

\begin{algorithm}{TEST}{Test Algorithm}\label{alg:TEST}%
\lipsum[2]
\end{algorithm}

The following link points to the theorem instead of the algorithm: \ref{alg:TEST}.

\end{document}

• \noindent\phantomsection – egreg Dec 17 '14 at 15:38

You need to set an anchor in the appropriate spot. This is done automatically when \refstepcounter is issued, but you have to do it manually when \@currentlabel is set without the help of a counter.

An anchor can be set with \phantomsection (it's a bad name, though).

\makeatletter
\newenvironment{algorithm}[2]%
{\medbreak
\edef\@currentlabel{#1}%
% more stuff here (put entry in table of algorithms, etc.)
\noindent\phantomsection % <------------------------ add the anchor
\textbf{Algorithm~\@currentlabel\ (#2)}\hfill\break
\ignorespaces}%
{\medbreak}
\makeatother


You could use the package's \hyperlink and \hypertarget macros. They don't require any counters, \refstepcounter actions, or redefinitions of \@currentlabel.

• Insert \hypertarget{<anchor name>}{<some text>} in the location to which the reader should jump.

• Insert \hyperlink{<anchor name>}{<other text>} in one or more locations from which the reader should jump, to the location specified elsewhere in the document by a \hypertarget instruction.

A very simple example:

\documentclass{article}
\begin{document}

\hypertarget{jump_destination}{\textbf{A wonderful tale}}

Once upon a time, \dots

\clearpage

\end{document}


The word "here" on the second page will be shown in blue, and clicking on it will take you to the line "A wonderful tale" on the preceding page.

It's possible to have multiple \hyperlink instructions pointing to the same anchor name, but there should be only one \hypertarget instruction for a given anchor name.

Adapting these ideas to your test code, it might look like this:

\documentclass{article}
\usepackage{lipsum,amsthm,hyperref}
\newtheorem{theorem}{Theorem}[section]

\newenvironment{algorithm}[2]%
{\par\medbreak\noindent
% more stuff here (put entry in table of algorithms, etc.)
\hypertarget{#1}{\textbf{Algorithm~#1 (#2)}}%
\par\noindent\ignorespaces}%
{\medbreak}

\begin{document}

\section{Test}

\begin{theorem}
\lipsum[1]
\end{theorem}

\begin{algorithm}{TEST}{Test Algorithm}
\lipsum[2]
\end{algorithm}

\clearpage

• Is there a way to make \ref{...} link to the correct spot using this approach? – jochen Dec 17 '14 at 19:25
• @jochen - \ref works in conjunction with \label which, in turn, typically requires some action that increments a counter and updates \@currentlabel in the process. (As egreg mentions in his answer, modifying \@currentlabel by hand isn't enough in your case -- one also needs to issue the instruction \phantomsection.) Given that you want an approach that doesn't involve any counter variables incremented by \refstepcounter, I think it's a good idea to rely on the \hyperlink/\hypertarget mechanism, which is provided by the hyperref package for just such a case. – Mico Dec 17 '14 at 21:41