WLJS LogoWLJS Notebook

Decorating symbols

We have significantly simplified the way you create syntax sugar for symbols compared to how it is done in Mathematica. You can still use low-level boxes such as RowBox, GridBox, etc., but we do not recommend it since it violates SOLID principles

Symbol decorations or syntax sugar are one of the main selling points of Wolfram Mathematica and WLJS Notebook. Basic math helpers such as fractions, square roots, and integrals significantly increase the readability of input and output expressions:


(*TB[*)Integrate[(*|*)(*FB[*)((Sin[x])(*,*)/(*,*)((*SqB[*)Sqrt[2](*]SqB*)))(*]FB*)(*|*), (*|*)x(*|*)](*|*)(*1:eJxTTMoPSmNmYGAo5gUSYZmp5S6pyflFiSX5RcGcQBHPvJLUdCA3NZMRpIgVSLgl5hSnAgCQTg44*)(*]TB*)

and this is how it actually looks like under-the-hood:

Integrate[Sin[x]/Sqrt[2], x]

Moreover, any Plot or Image is in fact just a fancy output form of corresponding Graphics and Image expressions and is fully editable! That's why the difference between input and output Wolfram Language cells in WLJS is rather vague.

Every symbol has its InputForm - this is how the expression can be typed by a user or serialized to a file, for example:

ListPlot[{0,1,2}] // InputForm
Graphics[{{}, Annotation[{{Annotation[{Directive[PointSize[0.012833333333333334], ...]}]}}]]

Then every symbol has its output form - how it is displayed in the cell or within other expressions. In WLJS we generally have 2 output forms:

If the output form is not defined, InputForm will be used. That's why all user-defined symbols look as they are in the output cells.

On output, expressions are processed with MakeBoxes - an internal symbol which is applied to any output. To define a form of expression, use the TagSet pattern:

MySymbol /: MakeBoxes[MySymbol, StandardForm] := "6"
MySymbol /: MakeBoxes[MySymbol, WLXForm]      := "9"

Depending on where this MySymbol is placed, it will look and work differently:

.slide ## Have a look at <MySymbol/>

or

MySymbol

6

The given example for StandardForm alters not only the appearance but also the output content: MySymbol is gone. This is rather discouraged in Wolfram Language, when you cannot retrieve the original expression from the output. To address this issue, we shall delve deeper into how to alter the displayed expression without changing the underlying one.

Interpretation

Temporary

You can temporarily replace a symbol with an icon by applying Interpretation. After the first evaluation, the representation is lost and the true expression is revealed:

Interpretation[ Graphics[Rectangle[{-1,-1},{1,1}], ImageSize->{20,20}], 1 ]

(*VB[*)(1)(*,*)(*"1:eJwlT8tOg0AAJMaD8SuwJyAQgahRk5osZlu2LyxLMEI4AF2B8tgGSoESPtS/keplMjPJTGbuAmp+XzEMU92OAHfJkZZ2Qhr8M0pOsDVX4Ll56R/iJKxck4RHv4gy4vaSIrKSMohsPxJl8EQW5X5EcHImrPTG9qossqo8eDwniGOFMFFeyaK1rDX9wPkm/ZoD6kQQ66f0cfmZrZH2oKc6OI151MGmjmncAJpHioFxuzrLxQwjCJOVpTotJs49AsDyDRRFzxBu9x3dvId2sHCKIF88+YWWz4KDgxLwggAC+7RKq+10Orns8GxN4P8fX49g1hnBNxdC/J1RZN2fa5U1+QVSjFNr"*)(*]VB*)

We can prove it by:

(*VB[*)(1)(*,*)(*"1:eJwlT8tOg0AAJMaD8SuwJyAQgahRk5osZlu2LyxLMEI4AF2B8tgGSoESPtS/keplMjPJTGbuAmp+XzEMU92OAHfJkZZ2Qhr8M0pOsDVX4Ll56R/iJKxck4RHv4gy4vaSIrKSMohsPxJl8EQW5X5EcHImrPTG9qossqo8eDwniGOFMFFeyaK1rDX9wPkm/ZoD6kQQ66f0cfmZrZH2oKc6OI151MGmjmncAJpHioFxuzrLxQwjCJOVpTotJs49AsDyDRRFzxBu9x3dvId2sHCKIF88+YWWz4KDgxLwggAC+7RKq+10Orns8GxN4P8fX49g1hnBNxdC/J1RZN2fa5U1+QVSjFNr"*)(*]VB*) + 1

2

Permanent

To permanently change how a given symbol is displayed, we should use MakeBoxes. Remember to apply MakeBoxes to any expression you want to provide to the output so it will propagate down the tree:

morse[s_String]; morse /: MakeBoxes[m: morse[s_], f: StandardForm] := With[{ i = Interpretation[Row[{"[", Style[s, 12], "]"}], m] }, MakeBoxes[i, f] ]

Let's define a helper constructor for our morse code:

morseTable = {"a" -> ".- ", "b" -> "-... ", "c" -> "-.-. ", "d" -> "-.. ", "e" -> ". ", "f" -> "..-. ", "g" -> "--. ", "h" -> ".... ", "i" -> ".. ", "j" -> ".--- ", "k" -> "-.- ", "l" -> ".-.. ", "m" -> "-- ", "n" -> "-. ", "o" -> "--- ", "p" -> ".--. ", "q" -> "--.- ", "r" -> ".-. ", "s" -> "... ", "t" -> "- ", "u" -> "..- ", "v" -> "...- ", "w" -> ".-- ", "x" -> "-..- ", "y" -> "-.-- ", "z" -> "--.. ", " " -> "/ "}; morse[s_String] := morse[StringReplace[ToLowerCase[s], morseTable]] /; StringMatchQ[s, ___~~WordCharacter..~~___]; morse /: TextString[morse[s_]] := StringReplace[s, Map[Function[r, Rule[r[[2]], r[[1]]]], SortBy[Normal[morseTable], -StringLength[Last[#]] &]]];

Let's try to create a morse code container:

morse["sos"]
(*VB[*)(morse["... --- ... "])(*,*)(*"1:eJxTTMoPSmNiYGAo5gISrimZJflFYZmp5cEngVwNLXenaC3N6mqlaCUNrRotTR0wqaHlBBLWUNLT01PQ1dVVANFKQGEdkJySoVWqV0VIiG9+QHCuX2aku2O+aXpysGNohGlUVHZBYXCetlNweJR2RJ5bYmR5unOISbprWEVwblRAIVA2OcI0KDI7Rzu0MtA3NL00I9MxyMupICS3oDy8Ij0sNDwqNTUnvTjKOdMgJ9DRtzA9vKLc1lYJZG+skxOIgrtSKVapthYo7A4UhviQBUgEleakBnOAGKmJKf55OZVg0ZCi0lQAzblJrw=="*)(*]VB*)

To check that this is still morse symbol, apply InputForm:

(*VB[*)(morse["... --- ... "])(*,*)(*"1:eJxTTMoPSmNiYGAo5gISrimZJflFYZmp5cEngVwNLXenaC3N6mqlaCUNrRotTR0wqaHlBBLWUNLT01PQ1dVVANFKQGEdkJySoVWqV0VIiG9+QHCuX2aku2O+aXpysGNohGlUVHZBYXCetlNweJR2RJ5bYmR5unOISbprWEVwblRAIVA2OcI0KDI7Rzu0MtA3NL00I9MxyMupICS3oDy8Ij0sNDwqNTUnvTjKOdMgJ9DRtzA9vKLc1lYJZG+skxOIgrtSKVapthYo7A4UhviQBUgEleakBnOAGKmJKf55OZVg0ZCi0lQAzblJrw=="*)(*]VB*) //InputForm
morse["... --- ... "]

Let's convert it back to the text:

(*VB[*)(morse["... --- ... "])(*,*)(*"1:eJxTTMoPSmNiYGAo5gISrimZJflFYZmp5cEngVwNLXenaC3N6mqlaCUNrRotTR0wqaHlBBLWUNLT01PQ1dVVANFKQGEdkJySoVWqV0VIiG9+QHCuX2aku2O+aXpysGNohGlUVHZBYXCetlNweJR2RJ5bYmR5unOISbprWEVwblRAIVA2OcI0KDI7Rzu0MtA3NL00I9MxyMupICS3oDy8Ij0sNDwqNTUnvTjKOdMgJ9DRtzA9vKLc1lYJZG+skxOIgrtSKVapthYo7A4UhviQBUgEleakBnOAGKmJKf55OZVg0ZCi0lQAzblJrw=="*)(*]VB*) // TextString
"sos"

Finally, make it audible:

silence = Table[0, {t,0,40Pi,0.1}]; dot = Table[Sin[5 t], {t,0,40Pi,0.1}]; dash = Join[dot, dot]; morse /: Play[morse[t_String]] := With[{ m = morse[t] }, Join @@ (Switch[#, ".", Join[dot, silence], "-", Join[dash, silence], _, Join[silence, silence]] & /@ StringSplit[m[[1]], ""]) // ListPlay // EmitSound; ];
(*VB[*)(morse["... --- ... "])(*,*)(*"1:eJxTTMoPSmNiYGAo5gISrimZJflFYZmp5cEngVwNLXenaC3N6mqlaCUNrRotTR0wqaHlBBLWUNLT01PQ1dVVANFKQGEdkJySoVWqV0VIiG9+QHCuX2aku2O+aXpysGNohGlUVHZBYXCetlNweJR2RJ5bYmR5unOISbprWEVwblRAIVA2OcI0KDI7Rzu0MtA3NL00I9MxyMupICS3oDy8Ij0sNDwqNTUnvTjKOdMgJ9DRtzA9vKLc1lYJZG+skxOIgrtSKVapthYo7A4UhviQBUgEleakBnOAGKmJKf55OZVg0ZCi0lQAzblJrw=="*)(*]VB*) // Play

ViewBox

Another way is to use Javascript with a custom display function. This can be done using ViewBox. Let's firstly define our display function as frontend symbol:

.js core.smileyDecorator = async (args, env) => { const canvas = document.createElement('canvas'); canvas.width = 50; canvas.height = 50; const ctx = canvas.getContext('2d'); // Draw a smiley face ctx.beginPath(); ctx.arc(25, 25, 20, 0, Math.PI * 2, true); // Outer circle ctx.moveTo(35, 25); ctx.arc(25, 25, 8, 0, Math.PI, false); // Mouth ctx.moveTo(22, 20); ctx.arc(20, 20, 2, 0, Math.PI * 2, true); // Left eye ctx.moveTo(32, 20); ctx.arc(30, 20, 2, 0, Math.PI * 2, true); // Right eye ctx.stroke(); //append to viewbox container env.element.appendChild(canvas); }
core.smileyDecorator%20%3D%20async%20%28args%2C%20env%29%20%3D%3E%20%7B%0A%20%20%20%20const%20canvas%20%3D%20document.createElement%28%27canvas%27%29%3B%0A%20%20%20%20canvas.width%20%3D%2050%3B%0A%20%20%20%20canvas.height%20%3D%2050%3B%0A%20%20%20%20const%20ctx%20%3D%20canvas.getContext%28%272d%27%29%3B%0A%20%20%20%20%2F%2F%20Draw%20a%20smiley%20face%0A%20%20%20%20ctx.beginPath%28%29%3B%0A%20%20%20%20ctx.arc%2825%2C%2025%2C%2020%2C%200%2C%20Math.PI%20%2A%202%2C%20true%29%3B%20%2F%2F%20Outer%20circle%0A%20%20%20%20ctx.moveTo%2835%2C%2025%29%3B%0A%20%20%20%20ctx.arc%2825%2C%2025%2C%208%2C%200%2C%20Math.PI%2C%20false%29%3B%20%20%2F%2F%20Mouth%0A%20%20%20%20ctx.moveTo%2822%2C%2020%29%3B%0A%20%20%20%20ctx.arc%2820%2C%2020%2C%202%2C%200%2C%20Math.PI%20%2A%202%2C%20true%29%3B%20%20%2F%2F%20Left%20eye%0A%20%20%20%20ctx.moveTo%2832%2C%2020%29%3B%0A%20%20%20%20ctx.arc%2830%2C%2020%2C%202%2C%200%2C%20Math.PI%20%2A%202%2C%20true%29%3B%20%20%2F%2F%20Right%20eye%0A%20%20%20%20ctx.stroke%28%29%3B%0A%20%20%20%20%2F%2Fappend%20to%20viewbox%20container%0A%20%20%20%20env.element.appendChild%28canvas%29%3B%0A%7D
The visible DOM element of ViewBox is provided as env.element property

Now we define a StandardForm for our symbol with ViewBox container. ViewBox allows to pass any decorator frontend symbol used to display an expression, and place any other expression underneath it in its InputForm:

SmileySymbol /: MakeBoxes[s_SmileySymbol, StandardForm] := With[{}, ViewBox[s, smileyDecorator[]] ] SmileySymbol[]

(*VB[*)(SmileySymbol[])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWkMIB4/iMjNzEmtdElNzi9KLMkvAgDDMArI"*)(*]VB*)

WLXForm output form does not support ViewBox, and all frontend symbols must be passed as FrontEndExecutable if we want to show it on a slide or markdown cell.

If you reevaluate the output cell, you will get the same decorated symbol. You can ensure that this is still the same symbol, by taking its first argument:

SmileySymbol[42]
(*VB[*)(SmileySymbol[42])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWkMIB4/iMjNzEmtdElNzi9KLMkvAgDDMArI"*)(*]VB*) // First

42

In this sense, this syntax sugar is not temporary but permanent. However, we can apply the same trick as before and use it to decorate other expressions temporarily:

Interpretation[SmileySymbol[], 1]
(*VB[*)(1)(*,*)(*"1:eJxTTMoPSmNiYGAo5gISrimZJflFYZmp5cHpQK6GVphTtJamRnBuZk5qZXBlblJ+TnSspoaWDlBQS8nQKtWrIiTENz8gONcvO9LdMT8q3TXYoyzb1Ds829fTyUQ/0zfLr8o1tyTFNcevKtPS28c3u8wx3cXF17HIUwlkRmyYk5YmxH4WIBFUmpMazAFipCam+OflVIJFQ4pKUwGOai6k"*)(*]VB*) - 1

0

Indicators

Here is another example. Let's create a gauge that can react to value changes. Define a gauge meter:

gauge[level_Real]; gauge /: MakeBoxes[g_gauge, StandardForm] := With[{}, ViewBox[g, g] ]

Here we use identical display and input expressions, the last one has to be defined as a frontend symbol too:

.js function setNeedlePosition(needle, value) { value = Math.max(0, Math.min(1, value)); const angle = value * 180 - 90; needle.style.transform = 'rotate('+Math.round(angle)+'deg)'; } core.gauge = async (args, env) => { const gauge = document.createElement('div'); gauge.style.width = '100px'; gauge.style.height = '50px'; gauge.style.border = '1px solid #000'; gauge.style.borderRadius = '50px 50px 0 0'; gauge.style.position = 'relative'; gauge.style.background = 'linear-gradient(to right, red 0%, yellow 50%, green 100%)'; const needle = document.createElement('div'); needle.style.width = '2px'; needle.style.height = '40px'; needle.style.background = '#000'; needle.style.position = 'absolute'; needle.style.bottom = '0'; needle.style.left = '50%'; needle.style.transformOrigin = 'bottom'; const pos = await interpretate(args[0], env); setNeedlePosition(needle, pos); gauge.appendChild(needle); env.element.appendChild(gauge); }
%0Afunction%20setNeedlePosition%28needle%2C%20value%29%20%7B%0A%20%20%20%20value%20%3D%20Math.max%280%2C%20Math.min%281%2C%20value%29%29%3B%0A%20%20%20%20const%20angle%20%3D%20value%20%2A%20180%20-%2090%3B%0A%20%20%20%20needle.style.transform%20%3D%20%60rotate%28%24%7Bangle%7Ddeg%29%60%3B%0A%7D%0A%0Acore.gauge%20%3D%20async%20%28args%2C%20env%29%20%3D%3E%20%7B%0A%20%20const%20gauge%20%3D%20document.createElement%28%27div%27%29%3B%0A%20%20gauge.style.width%20%3D%20%27100px%27%3B%0A%20%20gauge.style.height%20%3D%20%2750px%27%3B%0A%20%20gauge.style.border%20%3D%20%271px%20solid%20%23000%27%3B%0A%20%20gauge.style.borderRadius%20%3D%20%2750px%2050px%200%200%27%3B%0A%20%20gauge.style.position%20%3D%20%27relative%27%3B%0A%20%20gauge.style.background%20%3D%20%27linear-gradient%28to%20right%2C%20red%200%25%2C%20yellow%2050%25%2C%20green%20100%25%29%27%3B%0A%0A%20%20const%20needle%20%3D%20document.createElement%28%27div%27%29%3B%0A%20%20needle.style.width%20%3D%20%272px%27%3B%0A%20%20needle.style.height%20%3D%20%2740px%27%3B%0A%20%20needle.style.background%20%3D%20%27%23000%27%3B%0A%20%20needle.style.position%20%3D%20%27absolute%27%3B%0A%20%20needle.style.bottom%20%3D%20%270%27%3B%0A%20%20needle.style.left%20%3D%20%2750%25%27%3B%0A%20%20needle.style.transformOrigin%20%3D%20%27bottom%27%3B%0A%0A%20%20const%20pos%20%3D%20await%20interpretate%28args%5B0%5D%2C%20env%29%3B%0A%20%20setNeedlePosition%28needle%2C%20pos%29%3B%0A%0A%20%20gauge.appendChild%28needle%29%3B%0A%20%20env.element.appendChild%28gauge%29%3B%0A%7D%0A%0Acore.gauge.update%20%3D%20async%20%28args%2C%20env%29%20%3D%3E%20%7B%0A%20%20const%20val%20%3D%20await%20interpretate%28args%5B0%5D%2C%20env%29%3B%0A%20%20setNeedlePosition%28env.element.firstChild.firstChild%2C%20val%29%3B%0A%7D%0Acore.gauge.destroy%20%3D%20%28%29%20%3D%3E%20%7B%7D%0Acore.gauge.virtual%20%3D%20true%3B

Let's test it:

gauge[0.3]

(*VB[*)(gauge[0.3])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRAeK5BITyxNTy0yBoPL9gCxdwlI"*)(*]VB*)

You can also place it with other wolfram expressions

gauge[0.3] // Framed

For the next step, we need to define prototypes for our symbol to update the needle position and enable instancing:

.js //old definitions... core.gauge.update = async (args, env) => { const val = await interpretate(args[0], env); setNeedlePosition(env.element.firstChild.firstChild, val); } core.gauge.destroy = () => {} core.gauge.virtual = true;

Now let's provide a symbol to gauge and manipulate it with a slider:

meterLevel = 0.5; gauge[meterLevel // Offload] EventHandler[InputRange[0,1,0.1], (meterLevel = #)&]

(*VB[*)(gauge[Offload[meterLevel]])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRAeK5BITyxNT4Vw2YGEf1paTn5iSjEXkJ2bWpJa5JNalpoDAKdSDsA="*)(*]VB*)
(*VB[*)(EventObject[<|"Id" -> "42c994fc-168b-42e8-b5bb-0913fd5562e3", "Initial" -> 0.5, "View" -> "57468784-2fd4-4991-94b8-1b8fdcc3d093"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKm5qbmFmYW5joGqWlmOiaWFoa6lqaJFnoGiZZpKUkJxunGFgaAwBzLBUw"*)(*]VB*)

Try to drag it - it is alive!

ArrangeSummaryBox

This is a default display structure in Wolfram Language shared across many symbols like ColorData, NumericArray, ByteArray, and many more, which keeps the original expression hidden and instead shows some stats or details about the content.

For example, we have a symbol with information inside its arguments:

specialSymbol[<|"Date" -> Now, "Color" -> Red, "State" -> True|>]

Let's decorate it:

specialSymbol%20%2F%3A%20MakeBoxes%5Bobj%20%3A%20specialSymbol%5Basc_Association%5D%2C%20StandardForm%5D%20%3A%3D%20%0A%20%20%20%20Module%5B%7Babove%7D%2C%0A%20%20%20%20%20%20%20%20above%20%3D%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22Date%3A%20%22%2C%20asc%5B%22Date%22%5D%7D%5D%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22Color%3A%20%22%2C%20asc%5B%22Color%22%5D%7D%5D%7D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22State%3A%20%22%2C%20asc%5B%22State%22%5D%7D%5D%7D%0A%20%20%20%20%20%20%20%20%7D%3B%0A%0A%20%20%20%20%20%20%20%20BoxForm%60ArrangeSummaryBox%5B%0A%20%20%20%20%20%20%20%20%20%20%20specialSymbol%2C%20(*%20Head%20*)%0A%20%20%20%20%20%20%20%20%20%20%20obj%2C%20%20%20%20%20%20%20%20%20%20%20(*%20Input%20expression%20*)%0A%20%20%20%20%20%20%20%20%20%20%20None%2C%20%20%20%20%20%20%20%20%20%20(*%20Icon%20*)%0A%20%20%20%20%20%20%20%20%20%20%20above%2C%20%20%20%20%20%20%20%20%20(*%20Summary%20content%20*)%0A%20%20%20%20%20%20%20%20%20%20%20Null%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%5D%3B

The result looks like this:

specialSymbol[<|"Date" -> Now, "Color" -> Red, "State" -> True|>]

specialSymbol[(*VB[*) <|"Date" -> DateObject[{2026, 2, 2, 11, 28, 25.895413}, "Instant", "Gregorian", 1.], "Color" -> RGBColor[1, 0, 0], "State" -> True|> (*,*)(*"1:eJzFU0uPmzAQTt+PS4+VemoPPuwlAhMS0hvmFaKQBZxEmz2VDQ6iAXtrHCX5j/ujakO63Uo99CVVgvHMN+P5Rt/IH25Yun3S6/Wad9IgdvQZrz/ZnGe0IDne13XGTxLePlI1b6TxOaPCo/mq5GKfVV3iqTQTVuWtM2eUdD1VNCsb8b2ojR6r6O0DvjNPKEi9KskBP5c5NxPk4/uu9rU0Xl4KxlX6R8oueiXNMp25ZMNygi8kBqAFoL1CwETyBHAsAdXz8uYz2QiFjhDU4BBAB55/XVeOpYzZt8bmQDfAULP6+tAcjUcWHEDdMPQhGLmyBEAY0kZkVEiviwNOCsbLjHaI3pe3gel23O0Qzv0orQN1YNhkelwsIhbjel6uA5uZxRKvr+tbEw9vT9vKL/GVmW68JkHB1XE6W669XZFYOyPWAPQRjjwxX1J0itxwEU0SLeLhoeHhyt7ZHjrEuACGqz410gNu012ddekkVnKm+4rgl8ohWX5Jq1OLLvie/O4CX8icwyrG/3SDd72fbzANUNtXYnorp6Z9O/6h0BM6iJ1kHmRJbJPEmUyNTTOKT9j6si4cV/L41wkqIpfanj0ol3H630TG4i+eyT3xLwzXPFNvP6sa8hWDJQpB"*)(*]VB*)]

This is still a valid input expression unless it was too large, in which case it will be indicated by a label: "Data is on Kernel". This means that you can still evaluate it in the current session, but the data is not stored in the notebook and will be lost if you restart the evaluation kernel.

Now add an icon based on the "Color" field. Note that the icon can only be Image, Image3D, Graphics, Graphics3D, None, or any frontend symbol:

specialSymbol%20%2F%3A%20MakeBoxes%5Bobj%20%3A%20specialSymbol%5Basc_Association%5D%2C%20StandardForm%5D%20%3A%3D%20%0A%20%20%20%20Module%5B%7Babove%2C%20icon%7D%2C%0A%20%20%20%20%20%20%20%20above%20%3D%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22Date%3A%20%22%2C%20asc%5B%22Date%22%5D%7D%5D%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22Color%3A%20%22%2C%20asc%5B%22Color%22%5D%7D%5D%7D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%7BBoxForm%60SummaryItem%5B%7B%22State%3A%20%22%2C%20asc%5B%22State%22%5D%7D%5D%7D%0A%20%20%20%20%20%20%20%20%7D%3B%0A%0A%20%20%20%20%20%20%20%20icon%20%3D%20Graphics%5B%7B%0A%20%20%20%20%20%20%20%20%20%20Lighter%5Basc%5B%22Color%22%5D%5D%2C%20Disk%5B%7B0%2C0%7D%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20%20%20asc%5B%22Color%22%5D%2C%20Disk%5B%7B0%2C0%7D%2C%200.8%5D%0A%20%20%20%20%20%20%20%20%7D%2C%20%0A%20%20%20%20%20%20%20%20%20%20ImageSize%20-%3E%20%7B50%2C%2050%7D%2C%20%0A%20%20%20%20%20%20%20%20%20%20ImagePadding%20-%3E%20None%2C%20%0A%20%20%20%20%20%20%20%20%20%20Controls%20-%3E%20False%2C%0A%20%20%20%20%20%20%20%20%20%20PlotRange%20-%3E%20%7B%7B-1%2C1%7D%2C%7B-1%2C1%7D%7D%0A%20%20%20%20%20%20%20%20%5D%3B%0A%0A%20%20%20%20%20%20%20%20BoxForm%60ArrangeSummaryBox%5B%0A%20%20%20%20%20%20%20%20%20%20%20specialSymbol%2C%0A%20%20%20%20%20%20%20%20%20%20%20obj%2C%0A%20%20%20%20%20%20%20%20%20%20%20icon%2C%0A%20%20%20%20%20%20%20%20%20%20%20above%2C%0A%20%20%20%20%20%20%20%20%20%20%20Null%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%5D%3B
specialSymbol[(*VB[*) <|"Date" -> DateObject[{2026, 2, 2, 11, 31, 53.514057}, "Instant", "Gregorian", 1.], "Color" -> RGBColor[1, 0, 0], "State" -> True|> (*,*)(*"1:eJzFVMmOm0AQdfblEimXSDklUvqQgy1oNntubN5kPCzGGc8pbWgjYqAnTVux/zEflcI4jg85ZJMiweuuV03V45Xg7ZqFmwedTqd+DWCx/ZDx8qPJOakymka7siT8APTmXnPmBcCQs0q4VbrMudiRok28vEi4e5rsBFkXNHoHtKEOqEokuatTRe2qCk26BJhuYui61CeUponeKngIMMtr0ZY8R/eb6NWFupOqiaDlMqdfoseQc4igV2/as88B3DQXjDfpH9XGrEjb6BlAHM4cmrCURu+BQ7iPsLm0kGbBivAAiKbm9foTTUTDGhaWsI6wjU+3LAMoDWhKT5NVSTMQvFFP7cuSivuarA0MrKvIcOAIwnhS1YJUAnZtPOI0YzwnVcvIPXgaaU7b+yjCPks5brCMFJNO94uFx/yonOerkcm0LI5Wt+WdFul3h00xzKMbLUzcOrBGN/vpLF652yzobxVfQnhoRZ4r5nFlHTxnsvDGgeTxFdzxB3NrumbghwFSnOZqJF301pzlyZfW4sbOcAcTftpsKEmvq+JwZBd8R393gE8gZ7OC8T+d4NfOzycYjqxjXeDko52S9H35h0aPK9W3g/mIBL5JA3s8VZLa8A9R//Mqsx3oM7wNrMxzKrBYzWM/zP6XyZH4i8/k3PgXxNWPmh8CKWr6DeUsF20="*)(*]VB*)]
Place Refresh or any other expression that support live updates to one of the summary fields for live state display
Place InputRange to one of the summary fields to mutate your state

On this page