How to construct a macro with key=value by \pgfkeys

I just learn \pgfkeys, but don't quite understand how to use it for making a macro with key=value options.

I'd like to give the following simple example as a practice to show my idea.

\documentclass{article}
\usepackage{tikz}

\newcommand{\mycolorbox}[1][]{
\pgfkeys{
color/.initial=red,
text/.initial=some text,
#1,
exe/.code=\colorbox{color}{text}
}
}
\begin{document}
\mycolorbox[color=blue, text=This is a practice.]
\end{document}


This does not work. Anyone can help me with this?

• take a look here
– JeT
Jun 8, 2021 at 8:32

You want to define your own namespace for keys and separate key definition from usage.

\documentclass{article}
\usepackage{tikz}

\pgfkeys{/lyl/mycolorbox/.cd, % define your own space
color/.store in=\mycolorboxcolor,
text/.store in=\mycolorboxtext,
color=red!40,
text=some text,
}

\newcommand{\mycolorbox}[1][]{%
\begingroup
\pgfkeys{/lyl/mycolorbox/.cd,#1}%
\colorbox{\mycolorboxcolor}{\mycolorboxtext}%
\endgroup
}

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}


The expl3 version:

\documentclass{article}
\usepackage{xcolor}

\ExplSyntaxOn

\keys_define:nn { lyl/mycolorbox }
{
color .tl_set:N  = \l__lyl_mycolorbox_color_tl,
text  .tl_set:N  = \l__lyl_mycolorbox_text_tl,
color .initial:n = red!40,
text  .initial:n = some~text,
}

\NewDocumentCommand{\mycolorbox}{O{}}
{
\group_begin:
\keys_set:nn { lyl/mycolorbox } { #1 }
\colorbox{\l__lyl_mycolorbox_color_tl}{\l__lyl_mycolorbox_text_tl}
\group_end:
}

\ExplSyntaxOff

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}


• Does that mean if I have 20 keys, then I have to use 20 macros to store them? in an article, maybe many commands needs key=value. So many marco names are too heavy to namespace? Do I understand it right?
– lyl
Jun 8, 2021 at 12:57
• @lyl There is plenty of memory space for macros, don't worry. Jun 8, 2021 at 13:07
• I tried this: \def\mycolorboxtext{aaa}\mycolorbox[color=blue!20], and aaa was typeset. Does that mean the namespace is polluted? It seems that \begingroup...\endgroup does not work?
– lyl
Jun 8, 2021 at 13:07
• @lyl I added an expl3 version that I'd prefer. Anyway, don't do \def\mycolorboxtext. Jun 8, 2021 at 13:12
• If you have lots of keys, I'd go for a programmatic set up of all of them Jun 8, 2021 at 13:12

Another way to store values is inside the key paths themselves (that doesn't mean you don't use as many commands, so this doesn't ease the namespace-heaviness).

\documentclass[]{article}

\usepackage{xcolor}
\usepackage{pgfkeys}

\pgfkeys
{%
/mycolorbox/.is family
,/mycolorbox
,color/.initial=blue
,text/.initial=some text
}
\newcommand\mycolorbox[1][]
{%
\begingroup
\pgfqkeys{/mycolorbox}{#1}%
\colorbox
{\pgfkeysvalueof{/mycolorbox/color}}
{\pgfkeysvalueof{/mycolorbox/text}}%
\endgroup
}

\begin{document}
\mycolorbox

\mycolorbox[color=red]

\mycolorbox[text=foobar]
\end{document}


(note: \pgfqkeys{/<path>}{<keys>} is the same as \pgfkeys{/<path>/.cd,<keys>} but faster)

• Thank you for this solution. And how does \begingroup...\endgroup here work?
– lyl
Jun 8, 2021 at 13:17
• \begingroup...\endgroup just keeps the changes to the options local to this one command, so that the next invocation isn't dependent on the previous one. The two commands (\begingroup and \endgroup) are TeX primitives. Jun 8, 2021 at 13:23
• Oh,I see. It's the cost of non-macro to store value of keys. Many thanks!
– lyl
Jun 8, 2021 at 13:44
• @lyl no, you'd do the same if you used macros to store the values. All that \pgfkeys{/foo/bar/.initial={<value>}} does is store the value inside a macro with a long name that is \pgfk@/foo/bar (slashes are part of the macro name). Jun 8, 2021 at 17:09

If you're just setting up a simple macro with a few keys (and that's the only interface accessing and using those keys), you could as well build your macro with expkv-cs:

\documentclass[]{article}

\usepackage{xcolor}
\usepackage{expkv-cs}

\ekvcSplit\mycolorbox
{
color=blue
,text=some text
}
{\colorbox{#1}{#2}}%

\begin{document}
\mycolorbox{}

\mycolorbox{color=red}

\mycolorbox{text=foobar}
\end{document}


(expkv-cs defines the macro \mycolorbox with a mandatory argument, if you want to use an optional one, just add a wrapper like: \newcommand\mycolorbox[1][]{\mycolorboxSplit{#1}} and changing the name of the macro after \ekvcSplit to \mycolorboxSplit).

• Many thanks for these good solution and suggestion!
– lyl
Jun 8, 2021 at 14:24