A Hands-on Introduction to
Formula Typesetting

Itai Seggev, Wolfram Research

#WolframTechConf

ABSTRACT

We will cover how "typesetting"—the transmission of expressions from the kernel to the notebook front end, and their display—is done for most mathematical objects in recent versions of Wolfram Language. Many of these objects can have their display customized; how to identify such objects and how to customize them will also be discussed. Some commonly used mathematical notations such as Kronecker δ, transposes, and Hermitian conjugates will be used as examples. As time permits, we will illustrate how you can use these techniques for your own objects.

Scope of this session

Prerequisites (will be briefly reviewed)

Basic knowledge of different cell and formatting types

Familiarity with the main loop

Goals

Identifying mathematical objects whose appearance can be customized

Customizing the appearance of those objects

How to apply these techniques to your own objects (?)

Deploying this formatting in paclets (?)

Non-goals:

Customizing the appearance of objects that are highly interactive

Deep discussion of the subtleties of the box language or formatting rules

Notebook programming

Key Tools

MakeBoxes

CurrentValue

Specifically, CurrentValue[{StyleDefinitions,style}]

TemplateBox

Cell ▶ Show Expression

a.k.a. (Key2[shift, ctrl, e]) (Linux/Windows) or (Key2[shift, cmd, e]) (Mac)

Format ▶ Edit Stylesheet...

The world’s fastest introduction to boxes and the main loop

Every cell in a notebook is represented by a WL expression

You can see the expression using  Cell ▶ Show Expression

“Textual” cells contain strings (or somewhat snazzified versions thereof)

“Text”, “Item”, “Section”, etc

Often these cells contain an explicit TextData head

“Two dimensional” or “typeset” cells use expressions in the “box language”

These can be identified by the presence of the BoxData head in the expression

Most input and output cells are of this type

The cells can be formatted in StandardForm or TraditionalForm

Cell ▶ Convert To can be used to change between formats and cell types

There are other, more specialized, cell types. Two that appear below are RawData and StyleData.

While beyond the scope of this session, cells/boxes can be programmatically read and modified using functions like NotebookRead and NotebookWrite.

This is an input cell:

2

The following displays the box representation of the preceding input cell:

Dynamic[InputForm@NotebookRead[Nest[PreviousCell,Unevaluated[Sequence[]],3]],UpdateInterval->.1]

Homework exercise: Convert To  ▶ InputForm vs Convert To  ▶ Raw InputForm

Convert the first input cell above to InputForm and Raw InputForm.  Explain what you see in terms of the concepts just introduced.

After Convert To  ▶ Raw InputForm, attempt to add a superscript in the cell.  What happens? Why is this necessary?

The main loop of a notebook-based Wolfram-Language session

After you hit (Key2[shift, , enter]), the following things happen:

The frontend standardizes the box expression of the input cell.

The frontend sends MakeExpression[boxes,StandardForm] (or MakeExpression[boxes,TraditionalForm], for those cells) to the kernel.

The kernel evaluates the sent expression. If the evaluation succeeds, as determined by producing an expression of the form HoldComplete[expr], the kernel goes on to the next step.  Otherwise, it sends an error to the frontend.

The kernel evaluates expr producing a result res.

If res is not Null, the kernel evaluates MakeBoxes[res,StandardForm] (or MakeBoxes[res,TraditionalForm]), producing a box expression. The output line number along with the box expression are sent to the frontend.

The frontend sticks the output line number and boxes in a cell and displays them.

The kernel sends the next input line number to the frontend, indicating the evaluation finished.

Additional notes

The three communication steps  (2, 5, and 7) can be observed using the LinkSnooper kernel available in the Evaluation menu.

There will be many more steps shown, due to the predictive interface, dynamics, symbol coloring, etc.

Roughly speaking the above steps can be grouped into three stages:

Steps 1-3 (especially 3) are the parsing stage

Step 4 is the evaluation stage

Steps 5-7 are the formatting stage

This session focuses on the formatting stage, and particularly on step 6, the receipt and display of boxes

TemplateBox

A TemplateBox is a construct that separates the display of an expression from its interpretation

This makes it easy to write MakeBoxes rules for the object, and unnecessary to write MakeExpression rules

The information for display and interpretation is still necessary, and can go in either the TemplateBox itself or in a stylesheet

Advantages of putting the display information in the stylesheet include:

Saving space in notebooks—all the common pieces are in the stylesheet

Display can be updated over time

Users can customize appearance

A TemplateBox has the basic structure

TemplateBox[{(Subscript[box, 1]),(Subscript[box, 2]),…},"name", options] or

TemplateBox[<|"(Subscript[key, 1])"->(Subscript[box, 1]),"(Subscript[key, 2])-">(Subscript[box, 2]),…|>,"name", options]

The two most important options, corresponding to the information mentioned above, are:

DisplayFunction

InterpretationFunction

We will focus on “simple” template boxes, which primarily use the list form with no options in the TemplateBox itself

Examples

Preamble: RawBoxes

RawBoxes:

has no evaluation rules, and

its formatting rule is “take my argument and use it as my box representation”

Example:

boxes=RowBox[{"2","+",SuperscriptBox["x","3"]}];

On evaluation, nothing happens (except boxes getting its value):

RawBoxes[boxes]//InputForm

On formatting, it generates boxes identical to its argument:

RawBoxes[boxes]

It used to extensively to display box expressions

Some expressions that use simple template boxes

Note the difference between the 2nd and 3rd outputs.

MakeBoxes[SinDegrees[x],TraditionalForm]//InputForm

MakeBoxes[BesselJ[n,z],TraditionalForm]//InputForm

MakeBoxes[KroneckerDelta[i,j],StandardForm]//InputForm

This is how the functions display:

RawBoxes/@{,,}

Some expressions that do not use template boxes

Sin  (because it’s old):

MakeBoxes[Sin[x],TraditionalForm]//InputForm

Integrate (because it’s old, and actually pretty complicated):

MakeBoxes[Integrate[f[x],x],StandardForm]//InputForm

Limit (because we wanted it to be “typeable”, like Integrate):

MakeBoxes[Limit[f[x],x->a],StandardForm]//InputForm

Display:

RawBoxes/@{,,}

Some expressions use template boxes that are not “simple”

Inactive[Integrate[…]] embeds the options inside the TemplateBox—can’t be customized:

MakeBoxes[Inactive[Integrate][f[x],x]]

FoxH uses nested template boxes—need to worry about interaction between them, and other things that might use the inner pieces:

MakeBoxes[FoxH[{{{a1,1}},{}},{{{b1,3}},{}},z],TraditionalForm]//InputForm

Root is dynamic, and is split into many pieces not directly related the FullForm—not simple!

ToBoxes[Root[#^7-5&,3],StandardForm]//InputForm

Display:

RawBoxes/@{,,}

Stylesheets and TemplateBox options

If the DisplayFunction or InterpretationFuntion are not present in the TemplateBox, the FE gets their values from stylesheets:

For each option, the FE walks up the chain of stylesheets until it finds a value

It looks for definitions from a style whose name matches the name (the 2nd argument) of the TemplateBox

You can do this yourself by starting  with  Format ▶ Edit Stylesheet...,  using  Edit ▶ Find..., and chasing the “Inheriting base styles from _” links

In-class exercise: SinDegrees

Find out what stylesheet has the definitions for "SinDegrees"

For built-in functions, the styles essentially always come from that same place (literally or figuratively—more on that much later)

But if we don’t care where exactly they are set, it is much simpler to find what the values are using CurrentValue

CurrentValue[{StyleDefinitions,style}]

gives all the explicitly set definitions of style

CurrentValue[{StyleDefinitions,style,TemplateBoxOptions,DisplayFunction}]

gives the effective value for DisplayFunction, whether or not it is explicitly set

CurrentValue
{StyleDefinitions,style,TemplateBoxOptions,InterpretationFunction}]

does the same for InterpretationFunction

Example: SinDegrees

Applying this technique to the "SinDegrees" style, it has explicitly set TemplateBoxOptions of DisplayFunction and Tooltip:

CurrentValue[{StyleDefinitions,"SinDegrees"}]//InputForm

Directly extract the display function and save it for later:

df=CurrentValue[{StyleDefinitions,"SinDegrees",TemplateBoxOptions,DisplayFunction}]

The interpretation function isn’t explicitly set; this is its effective value:

CurrentValue[{StyleDefinitions,"SinDegrees",TemplateBoxOptions,InterpretationFunction}]

In-class exercise: RGBColor

Using the techniques described thus far, determine whether the 3-argument RGBColor is a “simple” template box that is a candidate for having its display customized.

Homework exercise: RGBColor

Not withstanding the results of the previous exercise, use the techniques described below to make RGBColor display as a colored disk. (Hint: find an appropriate special character to use; avoid graphics.)

What is lost in making this custom display?

What is gained? A hint for one aspect: attempt Copy as Plaintext into an external program

Details of DisplayFunction and InterpretationFunction

DisplayFunction

The boxes in the first argument of the TemplateBox are fed to the display function

For {(Subscript[box, 1]),(Subscript[box, 2]),…}, the (Subscript[box, i]) are fed as separate arguments: df[(Subscript[box, 1]),(Subscript[box, 2]),…]

For: <|"(Subscript[key, 1])"->(Subscript[box, 1]),"(Subscript[key, 2])"->(Subscript[box, 2]),…|>, the associate is fed as a whole, necessitating  using the of (Subscript[#key, 1]), etc. in the function

Because the function is typically applied by the FE, there are many restrictions on it:

It must be in the f[#1, #2, …]& form

The only “evaluation” allowed is the insertion of the boxes

No flow control (If, Switch, whatever) can be used

It must be completely self contained

In other words, only expressions in the box language are allowed in the body

Particularly the association form  can be more flexible, effectively through the use of Dynamic, but not part of this session

Whatever results from the application is displayed

Important: the pieces coming from the display function cannot be selected or edited; only the boxes in the relevant slots can be (or the whole TemplateBox).

Tip: some styles you may want to use around some pieces:

ShowSyntaxStyles->False especially if the formatting is also used in StandardForm.

SingleLetterItalics->False, especially if the formatting is for TraditionalForm.

Example: SinDegress

SinDegrees[x]//TraditionalForm

Look at the boxes

MakeBoxes[SinDegrees[x],TraditionalForm]//InputForm

Feed the (Subscript[box, i]) as arguments to the display function:

df["x"]

This can be simulated using BoxForm`TemplateBoxToDisplayBoxes[tp]:

BoxForm`TemplateBoxToDisplayBoxes[]

Display the boxes:

RawBoxes@

InterpretationFunction

The (Subscript[box, i]) are fed to the interpretation function in the same way as to the display function

The result is then given to MakeExpression, which processes it normally

What if the function is Automatic?

Boxes are created representing head[(Subscript[x, 1]),(Subscript[x, 2]),…] where head is the symbol corresponding to the name in the TemplateBox and the (Subscript[x, i]) correspond to the (Subscript[box, i])

Example: SinDegress

Recall the InterpretationFunction of "SinDegrees" was Automatic;  use BoxForm`TemplateBoxToInterpretationBoxes[tp] instead of manual construction:

BoxForm`TemplateBoxToInterpretationBoxes[MakeBoxes[SinDegrees[x],TraditionalForm]]

Apply MakeExpression; notice that the result is wrapped in HoldComplete, as required:

MakeExpression[,TraditionalForm]

Customizing Appearance

To customize the appearance of a TemplateBox in a notebook:

Write a new display function df

If it is a tweak of the existing display, look up the current display function and modify it as needed

If it is completely different, typing in the expression with variables, unformatting the cell, and the replacing the variables with slots is a good way to get started

Create an expression of the form TemplateBoxOptions->{DisplayFunction->df}

=> I would do this in a normal notebook.  It’s easier to edit

=> The braces are important

=> Don’t forget the parentheses around the pure function!

Use  Format ▶ Edit Stylesheet...

Click on Add New Style

In the pop-up, enter the name of the template box (without the quotes)

Unformat the newly created cell.  It is of the form Cell[StyleData["name"],…]

Paste this expression into the unformatted cell

Reformat the cell

Observe any instances of the TemplateBox update their appearance

Example 1: Customize SinDegrees to omit the degree sign

We already have the current display function:

df

Instead of x°, we want just x, so replace the inner RowBox with just #1:

RowBox[{"sin","(",#1,")"}]&

Create the options expression:

TemplateBoxOptions->{DisplayFunction->(RowBox[{"sin","(",#1,")"}]&)}

Watch how the following changes appearance as the style cell is formatted:

SinDegrees[x]//TraditionalForm

Example 2: Customize Binomial to use (Subscript[C, k]^n) instead of (({{n}, {k}}))

Here are the boxes; it looks like a simple TemplateBox:

MakeBoxes[Binomial[n,k],TraditionalForm]//InputForm

There is nothing funny in the default DisplayFunction:

CurrentValue[{StyleDefinitions,"Binomial",TemplateBoxOptions,DisplayFunction}]//InputForm

Type in and unformat the desired display:

Cell[BoxData[
 SubsuperscriptBox["C", "k", "n"]], "Input"]

Create the corresponding display function (note the order of the slots):

SubsuperscriptBox["C", #2, #1]&

Assemble the options:

TemplateBoxOptions->{DisplayFunction->(SubsuperscriptBox["C", #2, #1]&)}

Observe the following update:

Binomial[n,k]//TraditionalForm

Exercises

In-class exercise: ArcSinDegrees

Modify ArcSinDegrees to use arcsin rather than (sin^(-1)).  Optionally, add the degree symbol in the appropriate place.

In-class exercise: KroneckerDelta

Modify KroneckerDelta to use a superscript (as might be used in an inverse metric) in its display.

Is it possible to make KroneckerDelta[i,j] display as the so-called identity tensor, (Subscript[δ, j]^i)?  Why or why not?

In what other way are the TemplateBoxOptions different than the previous examples and exercises?  Why is this necessary?

In-class exercise: Transpose

There are multiple notations for Transpose, include (■^T) (what’s used by the system), (■^t), (■^tr), and ■'. Customize the default display function to use your favourite alternate notation.

Homework exercise: (Arc)SinDegrees redux

Redo the SinDegrees and ArcSignDegrees display functions so that they do not color as unknown symbols in Input cells.

Is the SingleLetterItalics option relevant to these template boxes?  Why or why not?

There’s more???

Transpose can take arrays, not just matrices:

a=ArraySymbol["a",{n,n,n}];
Transpose[a]

With arrays, there are more possible transpositions, so a second argument might be used.  Let’s try it; why is the output using T instead of tr???

Transpose[a,3]

Let’s look at the boxes:

=> Why is there just an "a" and not something for the whole array?

MakeBoxes[Transpose[a,3],StandardForm]//InputForm

It’s using a separate TemplateBox, with its own definitions:

CurrentValue[{StyleDefinitions,"Transpose2"}]

To make 2-argument Transpose also use tr, it’s necessary to customize this second style.  Here’s a quick way to generate the TemplateBoxOptions with T replaced by tr:

/. "T"->"tr"

A general pattern

If a function can take a variable number of arguments, there is typically more than one associated template

For “simple” template boxes, there will typically be one template per argument count

There are ways of dealing with a variable number of arguments in one template, but these are typically only useful for functions that accept an arbitrary number of arguments

There are cases where the same argument count has multiple templates, if the structures are quite different

This is very common in special functions:

The simplest or most common form will use a template called "name", while the others will use "nameN", where N is the number of arguments

For example:  "Gamma", "Gamma2", and "Gamma3"

Example: Gamma details

Confirm that the three named styles are used by Gamma:

{MakeBoxes[Gamma[x],TraditionalForm],MakeBoxes[Gamma[x,y],TraditionalForm],MakeBoxes[Gamma[x,y,z],TraditionalForm]}//InputForm

Their appearance isn’t significantly different from each other:

TraditionalForm[RawBoxes/@%]

The "Gamma" style  can rely on InterpretationFunction->Automatic:

CurrentValue[{StyleDefinitions,"Gamma"}]

The other two styles need a nontrivial interpretation:

Column[CurrentValue[{StyleDefinitions,#}]&/@{"Gamma2","Gamma3"}]

Homework exercise: Polygamma

Change the display of Polygamma to use the notation (Subscript[ψ, n]) rather than (ψ^((n))). Make sure it works for both ways of entering digamma.

Deployment—your customizations

Editing the private stylesheet only affects that notebook

The stylesheet can be saved in an appropriate location and used in other notebooks

If you wish to use the customized styles in all your notebooks, you can do the following:

Create the styles you want in the private stylesheet of a normal notebook (one that inherits from Default.nb)

Select the stylesheet notebook and click on Export or use  File ▶ Save As...

Save it as Default.nb in the following location

Dynamic@FileNameJoin[{$UserBaseDirectory,"SystemFiles","FrontEnd", "StyleSheets"}]

Restart the frontend

For paclet developers

Why paclets?

Enable the use of this modern, TemplateBox-based approach

No need for complicated (or even any) MakeExpression rules

No “autoloading” issues on interpretation

Without paclets, could use TemplateBox, but would have to embed the options into every one made or force users to install and use a custom stylesheet

Pieces of formatting for paclet objects:

MakeBoxes rules

Appropriate DisplayFunction and, if necessary, InterpretationFunction

A “CoreExtensions” notebook

We’ll consider each in turn

MakeBoxes rules

The LHS of a MakeBoxes rule has one of the three forms (possibly with additional restrictions using Condition)

MyObject /: MakeBoxes[MyObject[…], fmt: StandardForm|TraditionalForm] := …
MyObject /: MakeBoxes[MyObject[…], fmt: TraditionalForm] := …
MyObject /: MakeBoxes[MyObject[…], fmt: StandardForm] := …

The use of TagSetDelayed is to make sure the rule is associated with MyObject rather than MakeBoxes.  While the above is conventional, one could use UpSetDelayed instead.

Example: One argument

Here’s a typical MakeBoxes rule for a single-argument function:

MyObject /: MakeBoxes[
	MyObject[x_],
	fmt: StandardForm|TraditionalForm
] := TemplateBox[
	{MakeBoxes[x,fmt]},
	"MyObject"
]

Example: Two arguments

This is the obvious modification for two arguments:

MyObject /: MakeBoxes[
	MyObject[x_,y_],
	fmt: StandardForm|TraditionalForm
] := TemplateBox[
	{MakeBoxes[x,fmt], MakeBoxes[y,fmt]},
	"MyObject2"
]

Example: Four arguments

And the obvious generalization for 4 arguments:

MyObject /: MakeBoxes[
	MyObject[w_,x_,y_,z_],
	fmt: StandardForm|TraditionalForm
] := TemplateBox[
	{MakeBoxes[w,fmt],MakeBoxes[x,fmt], MakeBoxes[y,fmt],MakeBoxes[z,fmt]},
	"MyObject4"
]

This is getting tedious, so you might think you can write:

MyObject /: MakeBoxes[
	MyObject[w_,x_,y_,z_],
	fmt: StandardForm|TraditionalForm
] := TemplateBox[
	MakeBoxes[#,fmt]& /@ {w,x,y,z},
	"MyObject4"
]

But this leads to some very nasty consequences:

Hold[MyObject[Print[1],Echo[2], 3+3,(Sqrt[4])]]

Fortunately, this idiom is common enough we have a dedicated function for it: BoxForm`ListMakeBoxes, that takes a list and returns the list of boxes:

MyObject /: MakeBoxes[
	MyObject[w_,x_,y_,z_],
	fmt: StandardForm|TraditionalForm
] := TemplateBox[
	BoxForm`ListMakeBoxes[{w,x,y,z},fmt],
	"MyObject4"
]

Now there are no nasty surprises:

Hold[MyObject[Print[1],Echo[2], 3+3,(Sqrt[4])]]

Note: the display above is the fallback, since the current DisplayFunction is:

CurrentValue[{StyleDefinitions,"MyObject4",TemplateBoxOptions,DisplayFunction}]

In-class exercise: MakeBoxes versus  BoxForm`ListMakeBoxes

Explain why we had to use BoxForm`ListMakeBoxes[list,fmt] rather than MakeBoxes[list,fmt].

On more general MakeBoxes rules

This session focuses on objects that fit into the paradigm above. If it is necessary to write more complicated rules, that’s definitely possible, but then it becomes essential to guard against evaluation leaks. The standard reference for doing so is https://library.wolfram.com/infocenter/Courseware/377/.

Jason Harris’s workshop from 2021 contains more examples / discussion of general MakeBoxes rules.  Jason also gave a talk two days ago that covered some of this material along with a more detail discussion of what happens when typing into a typeset cell.

Appropriate *Functions

With the MakeBoxes rule, MyObject will now format, but it is not so pretty:

{MyObject[x],MyObject[x,y],MyObject[w,x,y,z]}

But they do work as input, up to a point:

{(MyObject[x]),(MyObject2[x, x]),(MyObject4[w, x, x, z])}//InputForm

Thus:

Every TemplateBox will need a matching DisplayFunction

If the TemplateBox name does not match the function name, an InterpretationFunction is needed

Obviously, for more complicate templates, a rule might be needed even if the names match

Creating a DisplayFunction is just like the exercises above of customizing appearance

The same technique can be applied to the InterpretationFunction if needed.

Example: "MyObject2"

Type in MyObject[x,y] and unformat the cell:

Cell[BoxData[
 RowBox[{"MyObject", "[", 
  RowBox[{"x", ",", "y"}], "]"}]], "Input"]

Copying out the contents of BoxData and replacing x and y with slots gives:

if=RowBox[{"MyObject", "[",  RowBox[{#1, ",", #2}], "]"}]&;

Suppose we want to format this as (Subscript[M, x]^y).  Repeat for the DisplayFunction:

Cell[BoxData[
 SubsuperscriptBox["M", "x", "y"]], "Input"]

I will also add ShowSyntaxStyles->False to prevent unknown symbol coloring and SingleLetterItalics->False to have consistent appearance in StandardForm and TraditionalForm:

df=SubsuperscriptBox[StyleBox["M",ShowSyntaxStyles->False,SingleLetterItalics->False],#1,#2]&;

Construct the desired TemplateBoxOptions expression:
	=> Note the addition of the Tooltip option

TemplateBoxOptions->{DisplayFunction->df,InterpretationFunction->if,Tooltip->"MyObject"}

Now just need to store this someplace in the stylesheet, and the following will format nicely:

MyObject[x,y]

Confirm the interpretation of the typeset form:

(MyObject2[x, y])//InputForm

We have a different font, but the same general appearance in TraditionalForm:

(MyObject2[x, y]) //TraditionalForm

Homework exercise: Rest of MyObject

Create the corresponding TemplatBoxOptions for "MyObject" and "MyObject4", assuming we want the appearance (Subscript[M, x]) and (Subscript[M, w,y]^(x,z)) for them.

Homework exercise: MyObject with pairs

Let us suppose that MyObject supported an additional syntax, MyObject[{x,y},{w,z}], which displays as (Subscript[, x]^y)(Subscript[M, w]^z).

Write a MakeBoxes rule to generate a "MyObject2Pair" TemplateBox for expressions of this form.

Is it necessary to write an InterpretationFunction? If yes, write it.  If not, explain why not.

Write an appropriate DisplayFunction and combine all the needed TemplateBoxOptions. Hint: use \[InvisiblePrefixScriptBase].

CoreExtensions

Core, Core-in-Memory, and CoreExtensions

Many slides ago, the stylesheet Core.nb was displayed, as if it were showing the contents of a same-named notebook.

That, however, was a lie

What was shown was in fact Core-in-Memory, which is a composite of:

The contents of the actual Core.nb in the layout, and

Contents of various CoreExtensions.nb provided by installed paclets

Core.nb is special

Unlike the other stylesheets, only the one in $InstallationDirectory is ever read

The styles are loaded at startup only

It cannot be edited except by special means

All the styles that are in subsections in Core-in-Memory come from Core.nb.

CoreExtensions.nb files:

Are normal notebooks, not (necessarily) style-definition notebooks

Are located in a particular path in paclets with a "FrontEnd" extension enabled

All their StyleData cells are slurped up and appended to Core-in-Memory

These appear as unsectioned cells at the end of Core-in-Memory in the frontend

Details of CoreExtensions

The paclet must declare a "FrontEnd" extension

tutorial/Paclets explains how to declare such extensions

The styles go in FrontEnd/Assets/Extensions/CoreExtensions.nb

Any cells in CoreExtensions.nb other than StyleData cells are ignored in creating Core-in-Memory

You can add commentary, sectioning, examples, generating code, etc.

On paclet installation / removable, Core-in-Memory will be regenerated

i.e., no need for a restart

Name clashes

If there are two identically named styles, the first one in Core-in-Memory wins

Since Core.nb always appears first, built-in-styles cannot be overridden by paclets

However, one paclet might hide another’s style

It might be a good idea to include the paclet name in the style name

Other TemplateBox tidbits in brief

TemplateBox takes many options, most of them documented. Two important ones:

CopyFunction: controls how copy and paste to external programs happens.  Rarely needs to be set, but understanding the default Automatic setting is worthwhile

Tooltip: tooltip to display when the mouse cursor is over the box.  Typically a string, it can be a general box expression.  The value Automatic displays the name of the TemplateBox.

Automatic actually does a bit more than that, but currently that isn’t available to paclets.

A TemplateBox can’t be typed in. It can, however, be inserted using an InputAlias. If a paclet provides a custom stylesheet, that could be used to provide input notation

In conclusion

TemplateBox provides a powerful, flexible mechanism for customizing the displayed expressions

Though only “simple” template boxes were covered here, there are literally hundreds of uses of these throughout the system

For better and (slightly) for worse, it provides a structured representation

This makes it straightforward to use in many situations

Prevents users from accidentally munging important pieces

Limits typability / editability—in cases where highly flexible representations are desired, this may not be the best (or only part of the) solution.

Paclets now have dedicated support for TemplateBox-based development via CoreExtensions.nb

In short, TemplateBox good, 2 legs bad!