Concise vs. readable: $reveal and {{{ }}}

Ye olde way of making a button that does different things and looks different, depending on some state tiddler, is to use $reveal. That can quickly add up to a lot of lines. Take e.g. the $:/core/ui/Buttons/timestamp, here trimmed down to the basics for demonstration purposes:

<$reveal type="nomatch" state="$:/config/TimestampDisable" text="yes">
<$button class=<<tv-config-toolbar-class>>>
<$action-setfield $tiddler="$:/config/TimestampDisable" $value="yes"/>
<$reveal type="match" state="$:/config/TimestampDisable" text="yes">
<$button class=<<tv-config-toolbar-class>>>
<$action-setfield $tiddler="$:/config/TimestampDisable" $value="no"/>

The same can be done in three lines using inline filtering:

<$button class=<<tv-config-toolbar-class>> set="$:/config/TimestampDisable" setTo={{{ [{$:/config/TimestampDisable}match[yes]then[no]else[yes]] }}}>
<$transclude tiddler={{{ [{$:/config/TimestampDisable}match[yes]then[$:/core/images/timestamp-off]else[$:/core/images/timestamp-on]] }}} />

Yeah, OK, the lines are a bit longer. But not so much. And yes, the $action-setfield inside the $button is discouraged anyway. If the condition was used in more places (e.g. button text), I’d probably define a variable and check that to shave some more bytes off. :wink:

I think the $reveal is more readable, but not by much, and one cannot ignore the very concise alternative, no? I’m forgoing the whole button content near-duplication…

Have a nice day


After studying BurningTreeC’s Multi-Columns and the heavy use of Filtered Transclusion, I’ve started using it more often to cut down on duplicated code.

After understanding what was going on; the idea of being able to specify Classes, States, and their Values with filtered transclusions makes it easier for me to track what I’m doing instead of scanning multiple groups of similar-looking code.

Using a lot of consistent indentation also helps in keeping things readable for me.

If the button is meant to be a one-off, special purpose button; I am normally okay using Action widgets inside the button, but I’ll still break out the actions if it is more generic or if I end up with too many levels of nested code.

1 Like

In another post it was proposed to have best practice scripting in TiddlyWiki. That means to derive a subset of wikitext based on the modern TiddlyWiki (I assume TW 5.1.23+).
Having all operators, wikitext rules and commands from 2004 up to 2023 in one place ( makes people confuse. While it is a feature to have many options to do the same thing in TW, but in real life I like to stick with one solution and if I can, over the time optimize it for better performance and maintainability. I create Yazd (abandoned now) to collect snippet of best practice wikitext, and macros to be used in different projects. Examples are toggle buttons, list-search, custom transclusion, set-get fields, set-get key/value in data/json tiddlers, create tiddlers using template, small UIs, setting tabs, …

A nitpick: use toggle instead of match ?

<$button class=<<tv-config-toolbar-class>> setTo={{{ [{$:/config/TimestampDisable}toggle[yes],[no]] }}}>
<$transclude tiddler={{{ [{$:/config/TimestampDisable}match[yes]then[$:/core/images/timestamp-off]else[$:/core/images/timestamp-on]] }}}/>

edit: Nevermind, toggle doesnt work if the text field is blank, so a match is probably better

Another usefull tip to avoid using list widget is the genesis widget, useful when we want to switch between several html tags/widget (but not applicable here)

I tend to use the list widget rather than reveal, both inside a button to conditionally label the button and in an external set of actions using the action= parameter

  • I think of reveal if I needed some of the animation features (but don’t), modern filters permit the same logic now in filters/list widgets.
  • now I use the button popup parameter to toggle the existence of a state tiddler to make the code even simpler if my button has more than one state.

I actually did try toggle first, since it’s also semantic for this context. But then I did have to put in extra checks for blank tiddlers, so that match became the more concise version after all.

@jeremyruston or @pmario: Is this a bug with toggle? In the docs it says, “If neither [parameter] is present [in the input], the first parameter takes precedence [and] is added to the list.” So, for a blank input it should just add the first parameter, right?

1 Like

How do you use toggle assuming text is not blank. To my best of knowledge it works only with actionlistops

It’s not that it dose not work without the actionlistops, it’s just you can’t make it permanent.

{{{ [[a]toggle[a],[b]] }}}
{{{ [[b]toggle[a],[b]] }}}
{{{ [[c]toggle[a],[b]] }}}

Compare these two buttons:

<$button> toggle sidebar (setfield)
<$action-setfield $tiddler="$:/state/sidebar" text={{{ [{$:/state/sidebar}toggle[yes],[no]] }}}/>

<$button> toggle sidebar (listops)
<$action-listops $tiddler="$:/state/sidebar" $field="text" $subfilter="+[toggle[yes],[no]]"/>
1 Like

I think this not the way to use toggle. But it’s a surprise to see it works for filter transclusion.

Edited it does not work for filter transclusion, try to store result and write to a field

I’ve found a fix:

<$button set="!!field" setTo={{{ [enlist{!!field}toggle[on],[off]] }}}>click</$button>


<$button set="!!field" setTo={{{ [enlist{!!field}cycle[on off]] }}}>click</$button>

EDIT: join[] for some reason also works (even though the output shouldn’t change):

  • This doesnt work: <$button set="!!field" setTo={{{ [{!!field}toggle[on],[off]] }}}>click</$button>
  • This does: <$button set="!!field" setTo={{{ [{!!field}toggle[on],[off]join[]] }}}>click</$button>

EDIT2: better solution, <$button set="!!field" setTo={{{ [{!!field}cycle[on off]last[]] }}}>click</$button>

Using the debug-log operator* (that will probably not make it into the core) one can easily see what’s going on:
Without enlist, the input to toggle is a list with a single empty item when the referenced tiddler or field does not exist

{{{ [{$:/temp/somesetting}debug-log[]toggle[on],[off]] }}}

However, with enlist there is no list at all:

{{{ [enlist{$:/temp/somesetting}debug-log[]toggle[on],[off]] }}}

I think, according to the toggle doc, the first parameter should be added in both cases. But it only happens in the second.

Have a nice day

* see and the demo site for the PR


I think you are limiting your choices, toggle is a filter operator and it does what it does independently of where and how its used in a filter.

  • it is a seperate matter if it is used to change a variable, or commit it’s result to a field.
  • I don’t think so, the first part of the filter is asking to enlist something that has no members, end of filter. This is normal behaviour.
  • You could test for is[blank] or use else if you want the filter to continue.

I like the debug-log operator idea, I have not tried it yet, but simply providing a package to install it may be enough. In time it would move to core if its found very useful.

  • I recently made a solution that introduced a new parser/pragma rule/wiki text character and I could see it too being generalised for the core, but since it doers not change anything in the core its somewhat independent in some ways its fine living in an optional package.
    • It can easily be modified, replaced or cloned when managed as a optional package.
1 Like

Is there a chance to publish this as a plugin?

Sure, but I’d maybe take a while. I haven’t made plugins yet.
The PR is only two files, one of which is the doc. Wrapping a plugin around that seems unnecessarily much work. If someone else were to do it while I figure out the plugin-making process, he/she would have my blessing to do so.

Have a nice day

Thank you!

By the way, Gatha can wrap your two files into a plugin in seconds.


If I’ve done everything correctly, then this should be the packaged plugin:
yaisog_debug-log-filter_v0.9.json (5.0 KB)

Getting the TW5 doc tiddler into the readme took me about an hour or so…

Have a nice day


Tested on Edge/Chrome 108 + TW 5.2.5 works like a charm.

Many thanks Yaisog.

a minor comment: see the license, it needs small correction for name and link.

Thanks a lot for your work !

1 Like

Are you sure about the license?

Licenses typically have a year like <initial data>-<now> like 2023- and then in 2023-2024 if you change something in 2024 …