Compare commits

...
Author SHA1 Message Date
Théophile DesmedtandGitHub d0a0198f49 Fix image reference for TiddlyWiki architecture (#10000)
Fix the broken reference to "TiddlyWiki Architecture.svg"
2026-08-29 23:26:01 +01:00
Jeremy Ruston b3279e348d Update Quine URL 2026-08-25 17:24:25 +01:00
Théophile DesmedtandGitHub 6680967875 Improve discoverability of the style attribute feature (#9975)
* Improve discoverability of the style attribute feature

* Add missing tiddler  "Style Attributes"
2026-08-21 09:04:34 +02:00
Mario PietschandGitHub f9d5ee0ad7 Add ButtonWidget examples and execution order (#9945)
Document the button widget with runnable test cases and explain how its
attributes combine.

* Add eleven test case tiddlers, listed by title prefix so a new one needs
  no edit to the widget page
* Describe the order in which a button runs body actions, to, message,
  popup, set and actions, whatever order they are written in
* Prefer class over a hardcoded style
2026-08-16 13:17:33 +02:00
Mario PietschandGitHub 68630c939d Docs only Groupedlists examples (#9954)
* Add GroupedLists examples

Document grouped lists with runnable test cases over a shared
bibliography sample.

* Cover plain grouping, search, tabs by first character, both combined,
  and grouping on one field while searching another
* Name the grouped field in one procedure, so the grouping changes in
  one line
* Import it with import-compound, and list the examples by tag so a new
  one needs no page edit
* Rewrite the opening paragraph, which described only the sidebar tabs

* Replace GroupedLists code dumps with examples

Turn the two sidebar tabs the page describes into runnable test cases,
and tighten how the examples handle an empty result.

* Give each new example its own dummy payload, and point the page at the
  live tabs instead of quoting core source
* Carry the values through the filter from the start, so an All tab with
  no matches yields nothing rather than the literal All
* Use the list-empty widget

* use tc-tiny-gap instead of -left -right
2026-08-16 13:16:04 +02:00
superuser-doesandGitHub 7efbd01801 update 5.4.0 release notes: there was no change to default code wrap (#9962) 2026-08-08 11:46:30 +02:00
Théophile DesmedtandGitHub 5143138c16 [DOCS] Update [[Custom Widgets]] with new example for overriding LinkWidget (#9961)
* [DOCS] Update [[Custom Widgets]] with new example for overriding LinkWidget

* fix: non-svg link icon are now sizing properly

* replace HelloThere by list-link in the example for robustness

* Add class to span for better styling in Custom Widgets

* Fix typo in Custom Widgets.tid documentation

* Improve doc by using the proper macro to link widgets

* Change font size style to important for title icon

Updated the font size style for the title icon to be important.

* Update transclude and slot elements in Custom Widgets

Provide a fallback if no body for the link is given

* Enhance link widget to show icons conditionally

Updated the link widget to conditionally display an icon next to the link based on the target tiddler's icon field. Modified the rendering logic to use a conditional statement for the icon display.

* Change transclude height to size in Custom Widgets
2026-08-07 22:05:06 +02:00
27 changed files with 1250 additions and 43 deletions
@@ -6,4 +6,4 @@ title: Data Management during Runtime
During the runtime the data of Tiddlywiki is stored in javascript objects. These objects are synchronized with the DOM-Representation of Tiddlywiki. This means every change of the original data of a Tiddler, fires an event which changes all DOM-Representations of the Tiddler and the javascript object. The bare-bones Wiki store is created during the boot process and is kept in a object called \$tw.Wiki. This object contains amongst others a hashmap of the different Tiddlers of Tiddlywiki. The Hashmap is used to store the javascript object representation of the different Tiddlers. Furthermore this object is used to manage the tiddlers during runtime, it provides methods for adding tiddlers, search tiddlers by name and delete tiddlers.
As shown in the picture below, every change at the DOM triggers an event which changes the corresponding widget which again changes the store of the tiddlers. The whole image shows how WikiText is parsed by a set of rules into the parse tree and this parse tree is rendered as a tree of widgets. This Rendertree is synchronised to the DOM. Every modification on the Rendertree provokes a start of the rendering-pipeline. As well as every change on the wikiText triggers an event at the RenderTree. This Process uses a selective updating so that only the changed parts are updated. This means only widgets which have to change the DOM in consequence of a changed tiddler are refreshed.
{{TiddlyWikiArchitecture.svg}}
{{TiddlyWiki Architecture.svg}}
@@ -1,18 +1,22 @@
created: 20150106180000000
modified: 20241204085601176
list: GroupedLists/Example/TypesTab GroupedLists/Example/ByField GroupedLists/Example/WithSearch GroupedLists/Example/WithTabs GroupedLists/Example/TabsWithSearch GroupedLists/Example/SearchAnotherField GroupedLists/Example/RecentTab
modified: 20260729194941115
tags: ListWidget Lists
title: GroupedLists
type: text/vnd.tiddlywiki
The following sidebar tabs give examples of grouped lists created by nesting.
A grouped list is made by nesting one list inside another. The outer list collects each distinct value of a field, and the inner list finds the tiddlers holding that value.
!! [[Types Tab|$:/core/ui/MoreSideBar/Types]]
TiddlyWiki uses the pattern in two of its sidebar tabs. The [[Types Tab|$:/core/ui/MoreSideBar/Types]] groups tiddlers by their `type` field, and sits under ''More'' in the sidebar. The [[Recent Tab|$:/core/ui/SideBar/Recent]] groups them by day, through the <<.mlink timeline>> macro. Both are reproduced as examples below.
For the "Types Tab", the outer list filter as shown below selects each discrete value found in the `type` field. The inner list filter selects all the (non-system) tiddlers with that type.
!! Interactive Examples
<<tw-code "$:/core/ui/MoreSideBar/Types">>
Each example is a runnable test case carrying its own sample data. Where a field is grouped on, it is named once in <<.def groupField>>, so the grouping can be changed without touching anything else.
!! [[Recent Tab|$:/core/ui/SideBar/Recent]]
<<<
<$list filter="[tag[GroupedLists]]">
The list in the "Recent Tab" is generated using the <<.mlink timeline>> macro. Here, the outer list filter selects each discrete day found in the `modified` field, while the inner list filter selects all the tiddlers dated the same day in the `modified` field.
<<tw-code "$:/core/macros/timeline">>
; <$link/>
: {{!!description}}
</$list>
<<<
@@ -0,0 +1,31 @@
title: ButtonWidget/Example/Accessibility
description: Add accessibility and metadata attributes such as aria-label, role, tabindex and data
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
A button can carry accessibility and metadata attributes that pass straight through to the HTML element. They have no visible effect, so this example shows the markup rather than a result:
* `aria-label` gives an accessible name when the label is only an icon
* `role` overrides the implied ARIA role
* `tabindex` sets the keyboard focus order
* `data-*` attaches custom data attributes for scripts
* `selectedAria` chooses which ARIA state `selectedClass` toggles
Inspect the button in your browser to see the attributes on the element.
+
title: Output
<$wikify name="button-accessibility" mode="inline" output="html"
text="""<$button aria-label="Close"
role="button"
tabindex="0"
data-action="close"
>
×
</$button>
""">
<$text text=<<button-accessibility>>/>
</$wikify>
@@ -0,0 +1,33 @@
title: ButtonWidget/Example/Actions
description: Run one or more ActionWidgets when the button is clicked, using the preferred actions attribute
modified: 20260725015330000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `actions` attribute holds one or more ActionWidgets that run when the button is clicked. This is the preferred way to give a button its behaviour, because the whole behaviour sits in one place instead of being spread over several attributes.
A button runs `actions` last, after `to`, `message`, `popup` and `set`. ButtonWidget lists the full order. A single `<$button to="HelloThere">Click Me</$button>` still needs no action string.
The procedure below runs //two// actions in a single click:
* one sets a message
* the other bumps a counter
Click ''Greet'' a few times to watch both update.
+
title: Output
\procedure greetActions()
<$action-setfield $tiddler="$:/state/greeting" text="Hello!"/>
<$action-setfield $tiddler="$:/state/greeting-count"
text={{{ [[$:/state/greeting-count]get[text]] :else[[0]] +[add[1]] }}}
/>
\end
<$button actions=<<greetActions>>>
Greet
</$button>
Message: <$text text={{$:/state/greeting}}/> (clicked <$text text={{{ [[$:/state/greeting-count]get[text]] :else[[0]] }}}/> times)
@@ -0,0 +1,34 @@
title: ButtonWidget/Example/DragAndDrop
description: Make a button draggable with dragTiddler or dragFilter
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
`dragTiddler` makes the button draggable and sets the single tiddler it carries. `dragFilter` carries a list of tiddlers produced by a filter instead.
Choose one of the two:
* `dragTiddler` is a single tiddler title to drag
* `dragFilter` is a filter whose results are dragged as a list
Drag the button onto the drop area to see the title it carries. Drag and drop needs a desktop browser.
+
title: Output
\procedure recordDrop()
<$action-setfield $tiddler="$:/state/dropped" text=<<actionTiddler>>/>
\end
<$button dragTiddler="HelloThere" class="tc-btn-invisible tc-tiddlylink">
Drag me
</$button>
<$droppable actions=<<recordDrop>>>
<div style="border: 1px dashed #999; padding: 0.5em; margin-top: 0.5em;">
Drop the button here
</div>
</$droppable>
Dropped title: <$text text={{$:/state/dropped}}/>
@@ -0,0 +1,54 @@
title: ButtonWidget/Example/DragFilter
description: Drag a list of tiddlers with dragFilter and receive it with listActions
modified: 20260725001110000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
`dragFilter` makes the button draggable and carries every tiddler the filter returns, where `dragTiddler` carries a single title.
The drop target chooses how it receives that payload:
* `actions` runs once per dragged tiddler, with the title in `<<actionTiddler>>`
* `listActions` runs once for the whole payload, with all titles in `<<actionTiddlerList>>`
This test case carries four payload tiddlers tagged `Concepts`. The button drags all four, so the drop area shows the whole list at once. Drag and drop needs a desktop browser.
+
title: Cascades
tags: Concepts
A cascade is a filter list that is evaluated in turn until one returns a result.
+
title: ColourPalettes
tags: Concepts
A colour palette is a tiddler holding the named colours used by the user interface.
+
title: Commands
tags: Concepts
Commands are the operations run by the Node.js server from the command line.
+
title: Filters
tags: Concepts
A filter is an expression that selects a list of tiddler titles from the wiki.
+
title: Output
\procedure recordDropList()
<$action-setfield $tiddler="$:/state/dropped-list" text=<<actionTiddlerList>>/>
\end
<$button dragFilter="[tag[Concepts]]" class="tc-btn-invisible tc-tiddlylink">
Drag four tiddlers
</$button>
<$droppable listActions=<<recordDropList>>>
<div style="border: 1px dashed #999; padding: 0.5em; margin-top: 0.5em;">
Drop the button here
</div>
</$droppable>
Dropped titles: <$text text={{$:/state/dropped-list}}/>
@@ -0,0 +1,30 @@
title: ButtonWidget/Example/Message
description: Send a widget message with the message and param attributes
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `message` attribute sends a widget message when the button is clicked. The `param` attribute passes a single value with it.
The two attributes work together:
* `message` is the message type to send
* `param` is the value delivered with the message
A `messagecatcher` receives the message here and shows the parameter. Click the button to send it.
+
title: Output
\procedure receiveMessage()
<$action-setfield $tiddler="$:/state/received" text=<<event-param>>/>
\end
<$messagecatcher $tm-sample-message=<<receiveMessage>>>
<$button message="tm-sample-message" param="Hello from param">
Send message
</$button>
</$messagecatcher>
Received param: <$text text={{$:/state/received}}/>
@@ -0,0 +1,42 @@
title: ButtonWidget/Example/NewTiddler
description: Create a tiddler from a template with the tm-new-tiddler message
modified: 20260725002340000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
`tm-new-tiddler` is a message the core already handles, so the button needs no catcher of its own.
* `message` is set to `tm-new-tiddler`
* `param` names a template tiddler, and the new tiddler starts out with that template's fields
This test case carries a `TaskTemplate` payload tiddler holding `tags`, `status` and `priority`. Open the ''TaskTemplate'' tab above to see it.
The message creates a draft and normally opens it for editing. A test case has no story river, so the table lists the drafts instead. Each click adds one row, and the new tiddler takes the next free title because the previous draft still exists.
+
title: TaskTemplate
tags: Task
status: open
priority: normal
Describe the task here.
+
title: Output
<$button message="tm-new-tiddler" param="TaskTemplate">
New task
</$button>
<table>
<tr><th>Click</th><th>New tiddler</th><th>tags</th><th>status</th><th>priority</th></tr>
<$list filter="[has[draft.title]sort[draft.title]]" counter="clickNumber">
<tr>
<td><<clickNumber>></td>
<td><$text text={{!!draft.title}}/></td>
<td><$text text={{!!tags}}/></td>
<td><$text text={{!!status}}/></td>
<td><$text text={{!!priority}}/></td>
</tr>
</$list>
</table>
@@ -0,0 +1,38 @@
created: 20260724134149482
description: Toggle a popup with the popup attribute and a companion reveal widget
modified: 20260725003054000
tags: $:/tags/wiki-test-spec
title: ButtonWidget/Example/Popup
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `popup` attribute names a state tiddler that stores the popup coordinates. A companion `reveal` widget reads that state to show or hide the content.
The button uses these attributes:
* `popup` is the state tiddler for the popup
* `selectedClass` highlights the button while the popup is open
* `popupAbsCoords` writes absolute coordinates when set to `yes`, rather than relative ones
Use `popupTitle` in place of `popup` when the state title should not be read as a text reference. Click the button to toggle the popup.
The `reveal` widget always creates a DOM element of its own: a `div` in block mode, a `span` in inline mode. The `tag` attribute sets that element explicitly. Wrapping the popup content in a `<div>` would add a second element, so this example sets `tag="div"` and puts the `tc-drop-down` class on the widget itself. The popup is then one element instead of two.
+
title: Output
<$button popup="$:/state/popup/demo" selectedClass="tc-selected">
Toggle popup
</$button>
<$reveal type="popup"
tag="div"
state="$:/state/popup/demo"
position="belowleft"
animate="yes"
class="tc-drop-down"
>
This is the popup content.
</$reveal>
@@ -0,0 +1,41 @@
title: ButtonWidget/Example/Presentation
description: Change the rendered element and appearance with tag, class, style and disabled
modified: 20260725003716000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
Several attributes control how the button looks and which element it renders:
* `tag` renders a different HTML element in place of `button`
* `class` adds one or more CSS classes
* `style` sets a full CSS style string
* `disabled` set to `yes` disables the button
Reach for `class` first and keep the rules in a stylesheet. One class restyles every button that uses it, follows the colour palette and stays under the user's control. A hardcoded `style` overrides the theme and has to be repeated at every button, so use it only when no class can do the job.
`style` sets the whole style attribute and replaces anything a `style.*` attribute wrote before it, so do not mix the two.
+
title: Output
<$button tag="a" class="tc-tiddlylink">
tag="a" renders a link element
</$button>
<$button class="tc-btn-big-green">
class uses a rule from the stylesheet
</$button>
<$button disabled="yes">
disabled="yes"
</$button>
<$button style.color="green">
style is the last resort
</$button>
<$button style="font-weight: bold;">
style is the last resort
</$button>
@@ -0,0 +1,52 @@
title: ButtonWidget/Example/SelectedState
description: Highlight the active button with selectedClass, set, setTo and default used together
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
This example combines four attributes so a row of buttons can show which colour is active:
* `set` and `setTo` write the chosen colour to a state tiddler
* `selectedClass` marks the button whose `setTo` matches the current value of `set`
* `default` gives the value to compare against while the `set` tiddler does not yet exist
Because `default` is `red`, the ''Red'' button starts out selected. Click another colour to move the selection.
+
title: Output
<!-- The inline <style> below is only for this self-contained test/development example.
For production, define styles in a tiddler tagged $:/tags/Stylesheet instead. -->
<style>
.demo-swatch {
padding: 0.2em 0.7em;
}
.demo-selected {
outline: 2px solid #1a73e8;
}
</style>
<$button set="$:/state/colour" setTo="red"
default="red"
class="demo-swatch tc-small-gap-right"
selectedClass="demo-selected"
>
Red
</$button>
<$button set="$:/state/colour" setTo="green"
default="red"
class="demo-swatch tc-small-gap-right"
selectedClass="demo-selected"
>
Green
</$button>
<$button set="$:/state/colour" setTo="blue"
default="red"
class="demo-swatch tc-small-gap-right"
selectedClass="demo-selected"
>
Blue
</$button>
Selected colour: <$text text={{{ [[$:/state/colour]get[text]] :else[[red]] }}}/>
@@ -0,0 +1,24 @@
title: ButtonWidget/Example/SetAndSetTo
description: Assign a value to a tiddler with the set and setTo attributes used together
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
`set` and `setTo` work as a pair to assign a value when the button is clicked:
* `set` names the storage location, a TextReference
* `setTo` is the value written to it
`set` points at the location //itself//, so it takes no curly brackets, unlike an ordinary transclusion.
Click a colour to write it to the state tiddler shown below.
+
title: Output
<$button set="$:/state/colour" setTo="red">Red</$button>
<$button set="$:/state/colour" setTo="green">Green</$button>
<$button set="$:/state/colour" setTo="blue">Blue</$button>
Selected colour: <$text text={{$:/state/colour}}/>
@@ -0,0 +1,37 @@
title: ButtonWidget/Example/SetField
description: Assign a field or index directly with setTitle, setField and setIndex
modified: 20260724235815000
tags: [[$:/tags/wiki-test-spec]]
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `set` attribute treats its value as a TextReference, which is ambiguous when a title contains `!!` or `##`. The `setTitle` group names the target directly instead.
The attributes work together:
* `setTitle` is the tiddler to change, with no TextReference parsing
* `setField` is the field to write, defaulting to `text`
* `setIndex` writes a data index instead of a field
* `setTo` is the value to assign
Click a button to set the `caption` field, then watch it update below.
+
title: Output
<$button setTitle="$:/state/demo"
setField="caption"
setTo="First"
class="tc-small-gap-right"
>
Set caption to First
</$button>
<$button setTitle="$:/state/demo"
setField="caption"
setTo="Second"
class="tc-small-gap-right"
>
Set caption to Second
</$button>
Caption is now: <$text text={{$:/state/demo!!caption}}/>
@@ -0,0 +1,173 @@
code-body: yes
created: 20260728220000000
description: Bibliography sample data shared by the GroupedLists examples
modified: 20260729180306417
title: GroupedLists/Bibliography
type: text/vnd.tiddlywiki-multiple
title: 3DWiki2011
bibtex-entry-type: InProceedings
bibtex-author: 3D Wiki Collective
bibtex-title: Spatial Notes in Three Dimensions
bibtex-date: 2011
+
title: 3rdWave2014
bibtex-entry-type: Article
bibtex-author: 3rd Wave Research Group
bibtex-title: Note Taking After the Desktop
bibtex-date: 2014
+
title: Aronsson2002
bibtex-entry-type: InProceedings
bibtex-author: Aronsson, Lars
bibtex-title: Operation of a Large Scale, General Purpose Wiki Website
bibtex-date: 2002
+
title: Atkinson2016
bibtex-entry-type: Article
bibtex-author: Atkinson, Paul
bibtex-title: Digital ethnographies
bibtex-date: 2016
+
title: Bakshi2016
bibtex-entry-type: Article
bibtex-author: Bakshi, Divya
bibtex-title: Hypertext and Feminisms: Voicing the Silence
bibtex-date: 2016
+
title: Barker2008
bibtex-entry-type: InProceedings
bibtex-author: Barker, Philip
bibtex-title: Using wikis and weblogs to enhance human performance
bibtex-date: 2008
+
title: Barker2008a
bibtex-entry-type: InProceedings
bibtex-author: Barker, Philip
bibtex-title: Using Wikis for Knowledge Management
bibtex-date: 2008
+
title: Bernstein2016
bibtex-entry-type: Book
bibtex-author: Bernstein, Mark
bibtex-title: Getting Started With Hypertext Narrative
bibtex-date: 2016
+
title: Dalgaard2001
bibtex-entry-type: InProceedings
bibtex-author: Dalgaard, Rune
bibtex-title: Hypertext and the Scholarly Archive: Intertexts, Paratexts and Metatexts at Work
bibtex-date: 2001
+
title: Dickinson2008
bibtex-entry-type: InProceedings
bibtex-author: Dickinson, Anne
bibtex-title: Is the e-Learning Object Create Interactive Accessible e-Learning Accessible?
bibtex-date: 2008
+
title: Finnemann2016
bibtex-entry-type: Article
bibtex-author: Finnemann, Niels Ole
bibtex-title: Hypertext configurations: Genres in networked digital media
bibtex-date: 2016
+
title: Frumkin2005
bibtex-entry-type: Article
bibtex-author: Frumkin, Jeremy
bibtex-title: The wiki and the digital library
bibtex-date: 2005
+
title: Maier2016
bibtex-entry-type: InCollection
bibtex-author: Maier, Carmen Daniela
bibtex-title: Hypertext and Hypermedia
bibtex-date: 2016
+
title: Morris2007
bibtex-entry-type: InProceedings
bibtex-author: Morris, Joseph C.
bibtex-title: DistriWiki: a distributed peer-to-peer wiki network
bibtex-date: 2007
+
title: Ruston2004
bibtex-entry-type: Book
bibtex-author: Ruston, Jeremy
bibtex-title: TiddlyWiki
bibtex-date: 2004
+
title: Rutherford2009
bibtex-entry-type: Thesis
bibtex-author: Rutherford, Jayne
bibtex-title: Graphical Input for TiddlyWiki
bibtex-date: 2009
+
title: Schaffert2006
bibtex-entry-type: InProceedings
bibtex-author: Schaffert, Sebastian
bibtex-title: IkeWiki: A semantic wiki for collaborative knowledge management
bibtex-date: 2006
+
title: Shang2016
bibtex-entry-type: Article
bibtex-author: Shang, Hui-Fang
bibtex-title: Online metacognitive strategies, hypermedia annotations, and motivation on hypertext comprehension
bibtex-date: 2016
+
title: Shang2016a
bibtex-entry-type: Article
bibtex-author: Shang, Hui-Fang
bibtex-title: Exploring demographic and motivational factors associated with hypertext reading by English as a foreign language students
bibtex-date: 2016
+
title: Skiba2005
bibtex-entry-type: Article
bibtex-author: Skiba, Diane J.
bibtex-title: Do your students wiki?
bibtex-date: 2005
+
title: Trentin2009
bibtex-entry-type: Article
bibtex-author: Trentin, Guglielmo
bibtex-title: Using a wiki to evaluate individual contribution to a collaborative learning project
bibtex-date: 2009
+
title: Truman2016
bibtex-entry-type: Article
bibtex-author: Truman, Gail
bibtex-title: Web Archiving Environmental Scan
bibtex-date: 2016
+
title: Wagner2004
bibtex-entry-type: Article
bibtex-author: Wagner, Christian
bibtex-title: Wiki: A technology for conversational knowledge management and group collaboration
bibtex-date: 2004
+
title: Wilson2007
bibtex-entry-type: Article
bibtex-author: Wilson, Tom D.
bibtex-title: Review of TiddlyWiki 2.1.3
bibtex-date: 2007
@@ -0,0 +1,45 @@
created: 20260728220100000
description: Group tiddlers by the value of a field chosen in one place
import-compound: [[GroupedLists/Bibliography]]
modified: 20260729185240642
tags: $:/tags/wiki-test-spec GroupedLists
title: GroupedLists/Example/ByField
type: text/vnd.tiddlywiki-multiple
title: Narrative
`groupField` names the field to group by. It is the only line to change when you want a different grouping.
Two nested lists do the work:
* `f.valuesAll` collects each distinct value of that field, sorted
* `f.tiddlersFor` returns the tiddlers holding one of those values
This test case imports 24 bibliography tiddlers from the `GroupedLists/Bibliography` payload. They came from a ~BibTeX import, so the field is `bibtex-author` rather than `author`.
Barker and Shang each published twice, so their groups list two titles. Set `groupField` to `bibtex-entry-type` to regroup the same data by publication type.
+
title: Output
\whitespace trim
<!-- bibtex-author<value> would make the field name the operator, which cannot be a variable, so f.tiddlersFor compares via get<groupField> -->
<!-- No trailing whitespace after the field name: it becomes part of the name and the list silently renders nothing -->
\procedure groupField() bibtex-author
\function f.valuesAll() [all[tiddlers]!is[system]has<groupField>each<groupField>get<groupField>sort[]]
\function f.tiddlersFor(value) [!is[system]has<groupField>] :filter[get<groupField>match<value>] +[sort[title]]
<$list filter="[f.valuesAll[]]" variable="_value">
<div class="tc-menu-list-item">
<<_value>>
<$list filter="[f.tiddlersFor<_value>]">
<div class="tc-menu-list-subitem">
<$link><$text text={{{ [<currentTiddler>get[bibtex-title]] :else[<currentTiddler>] }}}/></$link>
</div>
</$list>
</div>
</$list>
@@ -0,0 +1,51 @@
title: GroupedLists/Example/RecentTab
created: 20260729190100000
modified: 20260729190100000
description: Group tiddlers by day with the timeline macro, as the sidebar Recent tab does
tags: [[$:/tags/wiki-test-spec]] GroupedLists
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `timeline` macro groups tiddlers by the day found in a date field. The ''Recent'' tab in the sidebar is a single call to it, which is all the Output below is.
The nesting happens inside the macro:
* the outer filter uses `eachday` to yield one tiddler per distinct day
* the inner filter uses `sameday` to collect every tiddler falling on that day
* `dateField` chooses which field to read, so the same macro groups by `created` just as well as by `modified`
The five dummy payload tiddlers below carry hand set `modified` dates. Nothing else here has a date field, so they are exactly what the timeline finds.
Pass `format` to change how each day is headed, and `limit` to cap how many tiddlers are considered.
+
title: Output
\whitespace trim
<$transclude $variable="timeline" format="DDth MMM YYYY"/>
+
title: Alpha
modified: 20260103120000000
Modified on the third, later in the day.
+
title: Beta
modified: 20260103100000000
Modified on the third, earlier in the day.
+
title: Gamma
modified: 20260102120000000
Modified on the second, later in the day.
+
title: Delta
modified: 20260102100000000
Modified on the second, earlier in the day.
+
title: Epsilon
modified: 20260101120000000
Modified on the first.
@@ -0,0 +1,116 @@
created: 20260728224000000
description: Group by one field while the search box filters on another
import-compound: [[GroupedLists/Bibliography]]
modified: 20260729190424885
tags: $:/tags/wiki-test-spec GroupedLists
title: GroupedLists/Example/SearchAnotherField
type: text/vnd.tiddlywiki-multiple
title: Narrative
`searchField` names the field the search box looks at, which no longer has to be the field the list groups by.
Three definitions carry the split:
* `groupField` is `bibtex-entry-type`, so the groups and the tabs are publication types
* `searchField` is `bibtex-author`, so typing still matches people
* `f.tiddlersMatching` narrows the tiddlers first, and the groups are derived from whatever survives
Because the groups are computed after the search, a whole group disappears once none of its entries match. The tab strip is still built from the unfiltered data, so the tabs themselves stay put.
This test case carries the same `_TabButton` and `_TabContent` payload tiddlers as the previous example.
Type `bar` to leave only ''InProceedings'', holding Barker's two papers. The other tabs drop to zero and show the `emptyMessage` of the list.
+
title: Output
\whitespace trim
<!-- Filter operator suffixes cannot be variables, so search:<searchField> is impossible.
f.tiddlersMatching searches the extracted value as a title, which works whichever field it came from. -->
<!-- No trailing whitespace after the field name: it becomes part of the name and the list silently renders nothing -->
\procedure groupField() bibtex-entry-type
\procedure searchField() bibtex-author
\procedure searchLabel() Author
\function f.valuesAll() [all[tiddlers]!is[system]has<groupField>each<groupField>get<groupField>sort[]]
\function f.tiddlersMatching() [all[tiddlers]!is[system]has<groupField>] :filter[get<searchField>search:title{$:/temp/GroupedLists/search-other}]
\function f.valuesFound() [f.tiddlersMatching[]each<groupField>get<groupField>sort[]]
\function f.letters() [f.valuesAll[]] :map[uppercase[]split[]first[]] +[unique[]sort[]]
\function f.valuesFor(letter) [f.valuesFound[]] :filter[uppercase[]split[]first[]match<letter>]
\function f.valuesShown(letter) [f.valuesFound[]] :filter[<letter>match[All]] :else[f.valuesFor<letter>]
\function f.tiddlersFor(value) [f.tiddlersMatching[]] :filter[get<groupField>match<value>] +[sort[title]]
<!-- The inline style below is only for this self-contained example. For production, define styles in a tiddler tagged $:/tags/Stylesheet instead. -->
<style>.demo-group-filter { margin-bottom: 1em; }</style>
<$macrocall
$name="tabs"
tabsList="[[All]] [f.letters[]]"
default="All"
state="$:/state/GroupedLists/tab-other"
buttonTemplate="_TabButton"
template="_TabContent"
/>
+
title: _TabButton
code-body: yes
\whitespace trim
<$text text=<<currentTab>>/><span class="tc-tiny-gap-left">(<$count filter="[f.valuesShown<currentTab>]"/>)</span>
+
title: _TabContent
code-body: yes
\whitespace trim
<!-- tm-focus-selector takes the first match in the document, so .tc-search input would hit the sidebar search. -->
<div class="tc-search demo-group-filter">
<label>
<<searchLabel>>:<$edit-text
tiddler="$:/temp/GroupedLists/search-other"
tag="input"
type="search"
default=""
placeholder={{{ [[Filter by ]addsuffix<searchLabel>] }}}
class="tc-tiny-gap"
/>
</label>
<%if [[$:/temp/GroupedLists/search-other]get[text]minlength[1]] %>
<$button
class="tc-btn-invisible"
tooltip="Clear the filter"
aria-label="Clear the filter"
>
<$action-deletetiddler $tiddler="$:/temp/GroupedLists/search-other"/>
<$action-sendmessage $message="tm-focus-selector" $param=".demo-group-filter input"/>
{{$:/core/images/close-button}}
</$button>
<%endif%>
</div>
<$list filter="[f.valuesShown<currentTab>]" variable="_value">
<$list-empty>
//No matches//
</$list-empty>
<div class="tc-menu-list-item">
<<_value>>
<$list filter="[f.tiddlersFor<_value>]">
<div class="tc-menu-list-subitem">
<$link><$text text={{{ [<currentTiddler>get[bibtex-title]] :else[<currentTiddler>] }}}/></$link>
</div>
</$list>
</div>
</$list>
@@ -0,0 +1,111 @@
created: 20260728220400000
description: Combine the tab strip with a search box inside the tab panel
import-compound: [[GroupedLists/Bibliography]]
modified: 20260729190424885
tags: $:/tags/wiki-test-spec GroupedLists
title: GroupedLists/Example/TabsWithSearch
type: text/vnd.tiddlywiki-multiple
title: Narrative
`_TabContent` holds the search box as well as the list, so the search sits inside the panel and filters within the selected tab.
Which values each definition reads is the whole design:
* `f.letters` reads the //unfiltered// values, so tabs never disappear while you type and the selected tab cannot be stranded on an empty panel
* `f.valuesShown` reads the //filtered// values, so the counts follow the search and a tab showing zero tells you not to look there
This test case carries the same `_TabButton` and `_TabContent` payload tiddlers as the previous example, with the search box added to the panel.
The input is a sibling of the list rather than a child of anything that recomputes, which is what keeps the cursor in the box while you type.
Type `ba` and watch the counts change. Any tab whose count falls to zero shows the `emptyMessage` of the list instead of nothing at all.
+
title: Output
\whitespace trim
<!-- Filter operator suffixes cannot be variables, so search:<groupField> and bibtex-author<value> are impossible.
f.valuesFound searches the collected values as titles, f.tiddlersFor compares via get<groupField>. -->
<!-- No trailing whitespace after the field name: it becomes part of the name and the list silently renders nothing -->
\procedure groupField() bibtex-author
\procedure groupLabel() Author
\function f.valuesAll() [all[tiddlers]!is[system]has<groupField>each<groupField>get<groupField>sort[]]
\function f.valuesFound() [f.valuesAll[]] :filter[search:title{$:/temp/GroupedLists/search}]
\function f.letters() [f.valuesAll[]] :map[uppercase[]split[]first[]] +[unique[]sort[]]
\function f.valuesFor(letter) [f.valuesFound[]] :filter[uppercase[]split[]first[]match<letter>]
\function f.valuesShown(letter) [f.valuesFound[]] :filter[<letter>match[All]] :else[f.valuesFor<letter>]
\function f.tiddlersFor(value) [!is[system]has<groupField>] :filter[get<groupField>match<value>] +[sort[title]]
<!-- The inline style below is only for this self-contained example. For production, define styles in a tiddler tagged $:/tags/Stylesheet instead. -->
<style>.demo-group-filter { margin-bottom: 1em; }</style>
<$macrocall
$name="tabs"
tabsList="[[All]] [f.letters[]]"
default="All"
state="$:/state/GroupedLists/tab-search"
buttonTemplate="_TabButton"
template="_TabContent"
/>
+
title: _TabButton
code-body: yes
\whitespace trim
<$text text=<<currentTab>>/><span class="tc-tiny-gap-left">(<$count filter="[f.valuesShown<currentTab>]"/>)</span>
+
title: _TabContent
code-body: yes
\whitespace trim
<!-- tm-focus-selector takes the first match in the document, so .tc-search input would hit the sidebar search. -->
<div class="tc-search demo-group-filter">
<label>
<<groupLabel>>:<$edit-text
tiddler="$:/temp/GroupedLists/search"
tag="input"
type="search"
default=""
placeholder={{{ [[Filter by ]addsuffix<groupLabel>] }}}
class="tc-tiny-gap"
/>
</label>
<%if [[$:/temp/GroupedLists/search]get[text]minlength[1]] %>
<$button
class="tc-btn-invisible"
tooltip="Clear the filter"
aria-label="Clear the filter"
>
<$action-deletetiddler $tiddler="$:/temp/GroupedLists/search"/>
<$action-sendmessage $message="tm-focus-selector" $param=".demo-group-filter input"/>
{{$:/core/images/close-button}}
</$button>
<%endif%>
</div>
<$list filter="[f.valuesShown<currentTab>]" variable="_value">
<$list-empty>
//No matches//
</$list-empty>
<div class="tc-menu-list-item">
<<_value>>
<$list filter="[f.tiddlersFor<_value>]">
<div class="tc-menu-list-subitem">
<$link><$text text={{{ [<currentTiddler>get[bibtex-title]] :else[<currentTiddler>] }}}/></$link>
</div>
</$list>
</div>
</$list>
@@ -0,0 +1,60 @@
title: GroupedLists/Example/TypesTab
created: 20260729190000000
modified: 20260729190000000
description: Group tiddlers by their type, as the sidebar Types tab does
tags: [[$:/tags/wiki-test-spec]] GroupedLists
type: text/vnd.tiddlywiki-multiple
title: Narrative
`$:/core/Filters/TypedTiddlers` collects one tiddler per distinct type, and the inner list then finds every tiddler sharing that type.
The two lists do different jobs:
* the outer filter ends in `each[type]`, so it yields one representative tiddler per type rather than every tiddler
* the inner filter reads `{!!type}` from that representative, so `currentTiddler` is what carries the type from the outer list to the inner one
This is the code behind the ''Types'' tab in the sidebar, under ''More''. Open that tab to see it running over a real wiki.
The five dummy payload tiddlers below are the only ones here with a `type` field, so they are exactly what the list finds.
+
title: Output
\whitespace trim
<$list filter={{$:/core/Filters/TypedTiddlers!!filter}}>
<div class="tc-menu-list-item">
<$view field="type"/>
<$list filter="[type{!!type}!is[system]sort[title]]">
<div class="tc-menu-list-subitem">
<$link to={{!!title}}><$view field="title"/></$link>
</div>
</$list>
</div>
</$list>
+
title: Alpha
type: image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><circle cx="8" cy="8" r="7"/></svg>
+
title: Beta
type: image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect x="1" y="1" width="14" height="14"/></svg>
+
title: Gamma
type: text/plain
A plain text sample.
+
title: Delta
type: text/plain
Another plain text sample.
+
title: Epsilon
type: application/json
{"sample": true}
@@ -0,0 +1,82 @@
created: 20260728220200000
description: Narrow a grouped list with a search box
import-compound: [[GroupedLists/Bibliography]]
modified: 20260729185240642
tags: $:/tags/wiki-test-spec GroupedLists
title: GroupedLists/Example/WithSearch
type: text/vnd.tiddlywiki-multiple
title: Narrative
`search:title` filters the values collected by `f.valuesAll`, so the grouped list narrows while you type without the tiddlers themselves being searched.
Two definitions are added to the plain grouped list:
* `groupLabel` is the human readable name shown beside the input
* `f.valuesFound` applies the search to the collected values
An empty box is a no operation, so the whole list comes back. The clear button appears only once there is something to clear, and puts the cursor back in the input.
Type `ann` to match Dickinson and Finnemann, `wi` to match several at once, or `zzz` to fall through to the `emptyMessage` of the outer list.
+
title: Output
\whitespace trim
<!-- Filter operator suffixes cannot be variables, so search:<groupField> and bibtex-author<value> are impossible.
f.valuesFound searches the collected values as titles, f.tiddlersFor compares via get<groupField>. -->
<!-- tm-focus-selector takes the first match in the document, so .tc-search input would hit the sidebar search. -->
<!-- No trailing whitespace after the field name: it becomes part of the name and the list silently renders nothing -->
\procedure groupField() bibtex-author
\procedure groupLabel() Author
\function f.valuesAll() [all[tiddlers]!is[system]has<groupField>each<groupField>get<groupField>sort[]]
\function f.valuesFound() [f.valuesAll[]] :filter[search:title{$:/temp/GroupedLists/search}]
\function f.tiddlersFor(value) [!is[system]has<groupField>] :filter[get<groupField>match<value>] +[sort[title]]
<!-- The inline style below is only for this self-contained example. For production, define styles in a tiddler tagged $:/tags/Stylesheet instead. -->
<style>.demo-group-filter { margin-bottom: 1em; }</style>
<div class="tc-search demo-group-filter">
<label>
<<groupLabel>>:<$edit-text
tiddler="$:/temp/GroupedLists/search"
tag="input"
type="search"
default=""
placeholder={{{ [[Filter by ]addsuffix<groupLabel>] }}}
class="tc-tiny-gap"
/>
</label>
<%if [[$:/temp/GroupedLists/search]get[text]minlength[1]] %>
<$button
class="tc-btn-invisible"
tooltip="Clear the filter"
aria-label="Clear the filter"
>
<$action-deletetiddler $tiddler="$:/temp/GroupedLists/search"/>
<$action-sendmessage $message="tm-focus-selector" $param=".demo-group-filter input"/>
{{$:/core/images/close-button}}
</$button>
<%endif%>
</div>
<$list filter="[f.valuesFound[]]" variable="_value">
<$list-empty>
//No matches//
</$list-empty>
<div class="tc-menu-list-item">
<<_value>>
<$list filter="[f.tiddlersFor<_value>]">
<div class="tc-menu-list-subitem">
<$link><$text text={{{ [<currentTiddler>get[bibtex-title]] :else[<currentTiddler>] }}}/></$link>
</div>
</$list>
</div>
</$list>
@@ -0,0 +1,76 @@
created: 20260728220300000
description: Bucket the groups into tabs by first character, with a count per tab
import-compound: [[GroupedLists/Bibliography]]
modified: 20260729190424885
tags: $:/tags/wiki-test-spec GroupedLists
title: GroupedLists/Example/WithTabs
type: text/vnd.tiddlywiki-multiple
title: Narrative
The `tabs` macro takes its tab list from a filter, so here the tabs come out of the data: one per distinct first character, plus an ''All'' tab.
Three definitions feed it:
* `f.letters` collects the distinct first characters
* `f.valuesFor` selects the groups filed under one character
* `f.valuesShown` returns everything for ''All'', one character otherwise
This test case carries two payload tiddlers, `_TabButton` and `_TabContent`, because the `tabs` macro transcludes its caption and its panel by tiddler title and cannot take inline wikitext.
Matching is case insensitive, so `de Vries` and `De Vries` would share a tab. A character that is not a letter gets its own tab, which is why the sample data produces a `3` tab. Each caption carries the number of groups behind it, so no tab is a dead end.
+
title: Output
\whitespace trim
<!-- bibtex-author<value> would make the field name the operator, which cannot be a variable, so f.tiddlersFor compares via get<groupField> -->
<!-- No trailing whitespace after the field name: it becomes part of the name and the list silently renders nothing -->
\procedure groupField() bibtex-author
\function f.valuesAll() [all[tiddlers]!is[system]has<groupField>each<groupField>get<groupField>sort[]]
\function f.letters() [f.valuesAll[]] :map[uppercase[]split[]first[]] +[unique[]sort[]]
\function f.valuesFor(letter) [f.valuesAll[]] :filter[uppercase[]split[]first[]match<letter>]
\function f.valuesShown(letter) [f.valuesAll[]] :filter[<letter>match[All]] :else[f.valuesFor<letter>]
\function f.tiddlersFor(value) [!is[system]has<groupField>] :filter[get<groupField>match<value>] +[sort[title]]
<$macrocall
$name="tabs"
tabsList="[[All]] [f.letters[]]"
default="All"
state="$:/state/GroupedLists/tab"
buttonTemplate="_TabButton"
template="_TabContent"
/>
+
title: _TabButton
code-body: yes
\whitespace trim
<$text text=<<currentTab>>/><span class="tc-tiny-gap-left">(<$count filter="[f.valuesShown<currentTab>]"/>)</span>
+
title: _TabContent
code-body: yes
\whitespace trim
<$list filter="[f.valuesShown<currentTab>]" variable="_value">
<$list-empty>
//No matches//
</$list-empty>
<div class="tc-menu-list-item">
<<_value>>
<$list filter="[f.tiddlersFor<_value>]">
<div class="tc-menu-list-subitem">
<$link><$text text={{{ [<currentTiddler>get[bibtex-title]] :else[<currentTiddler>] }}}/></$link>
</div>
</$list>
</div>
</$list>
@@ -1,11 +1,10 @@
title: $:/changenotes/5.4.0/#9107
description: Update configuration defaults
description: Update default sidebar layout
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: usability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9107
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9107 https://github.com/TiddlyWiki/TiddlyWiki5/issues/9757
github-contributors: Jermolene
* Changed default sidebar layout from ''fixed-fluid'' to ''fluid-fixed''
* Changed ''Wrap long lines in code blocks'' default to ''No''
Changed default sidebar layout from ''fixed-fluid'' to ''fluid-fixed''
@@ -14,7 +14,7 @@ The iPad/iPhone app ''Quine'' makes it possible to view, edit and then save chan
Currently in its third major version, rewritten for iOS and iPadOS 26.0.
[[Download it here|https://apps.apple.com/us/app/TiddlyWiki51664603]].
[[Download it here|https://apps.apple.com/us/app/quine/id6761664603]].
Instructions for use:
@@ -28,4 +28,4 @@ Instructions for use:
*Quine also allows you to open, edit and save TiddlyWiki files stored with other cloud file providers
*Quine allows you to follow embedded WikiText links and canonical links to external files on cloud-like file providers which support "folder level sharing".
//Note that Quine is published independently of TiddlyWiki//
//Note that Quine is published independently of TiddlyWiki//
@@ -1,6 +1,6 @@
caption: button
created: 20131024141900000
modified: 20251101091926820
modified: 20260725015330000
tags: Widgets TriggeringWidgets
title: ButtonWidget
type: text/vnd.tiddlywiki
@@ -66,4 +66,40 @@ Press me!
</$button>
```
''Tip:'' Set ''class'' to `tc-btn-invisible tc-tiddlylink` to have a button look like an internal link.
! Order of execution
The order of the attributes written in wikitext does ''not'' matter.
A button can carry several of these attributes at once. They are not alternatives: every one that is present is used, and ''always in the order shown below''.
# ActionWidgets in the button body
# <<.attr to>>
# <<.attr message>>, with <<.attr param>>
# <<.attr popup>> or <<.attr popupTitle>>
# <<.attr set>> or <<.attr setTitle>>, with <<.attr setTo>>, <<.attr setField>> and <<.attr setIndex>>
# <<.attr actions>>
<<.tip """When a button does more than one thing, put the whole behaviour in the `actions` attribute. It keeps the behaviour in one place and runs it last, after every other attribute above. A single `<$button to="HelloThere">Click Me</$button>` needs no action string.""">>
Action widgets are refreshed before each one runs, so they see the results of the actions before them. Ordinary widgets wrapped around them are not. See [[ActionWidget Execution Modes]] when a value looks out of date.
! Examples
This button uses the <<.attr to>> attribute to navigate to the [[HelloThere]] tiddler, opening it in the story river. The optional <<.attr tooltip>> attribute sets the text shown on hover.
<$macrocall $name='wikitext-example-without-html'
src='<$button to="HelloThere" tooltip="Navigate to the HelloThere tiddler">
Open ~HelloThere
</$button>'/>
<<.tip """Set ''class'' to `tc-btn-invisible tc-tiddlylink` to have a button look like an internal link.""">>
! Interactive Examples
<<<
<$list filter="[prefix[ButtonWidget/Example/]]">
; <$link/>
: {{!!description}}
</$list>
<<<
@@ -1,5 +1,5 @@
created: 20221007144237585
modified: 20240422084734129
modified: 20260807190532419
tags: Concepts
title: Custom Widgets
type: text/vnd.tiddlywiki
@@ -79,3 +79,34 @@ Python
<$let test="Tiger">
<$codeblock code=<<test>>/>
</$let>""">>
In this example, we override the <<.wlink "LinkWidget">> widget to automatically display an icon next to the link if the target tiddler has an `icon` field. We use the <<.wlink "ParametersWidget">> widget to capture all attributes passed to the original link and forward them to the underlying widget via <<.wlink "GenesisWidget">>:
<<wikitext-example-without-html """\widget $link()
\function link.icon()
[<params-var>jsonget[to]else<currentTiddler>get[icon]]
\end link.icon
\function link.text()
[<params-var>jsonget[to]else<currentTiddler>]
\end link.text
\whitespace trim
<$parameters $params="params-var">
<$genesis
$type="$link"
$remappable="no"
$names="[<params-var>jsonindexes[]]"
$values="[<params-var>jsonindexes[]] :map[<params-var>jsonget<currentTiddler>]"
>
<%if [<link.icon>]%>
<span class="tc-tiddler-title-icon tc-titlebar" style="fill:currentColor;font-size:11pt!important">
<$transclude $tiddler=<<link.icon>> size="11pt"/>
</span>
<%endif%>
<$slot $name="ts-raw">
<$text text=<<link.text>> />
</$slot>
</$genesis>
</$parameters>
\end
<<list-links "[has[icon]]">>""">>
@@ -1,6 +1,6 @@
caption: HTML
created: 20131205160816081
modified: 20241025073517909
modified: 20260821065251883
tags: WikiText
title: HTML in WikiText
type: text/vnd.tiddlywiki
@@ -68,26 +68,4 @@ In an extension of conventional HTML syntax, attributes of elements and widgets
!! Style Attributes
TiddlyWiki supports the usual HTML ''style'' attribute for assigning CSS styles to elements:
```
<div style="color:red;">Hello</div>
```
<<.from-version "5.2.2">> In an extension to HTML, TiddlyWiki also supports accessing individual CSS styles as independent attributes. For example:
```
<div style.color="red">Hello</div>
```
The advantage of this syntax is that it simplifies assigning computed values to CSS styles. For example:
```
<div style.color={{!!color}}>Hello</div>
```
<<.from-version "5.3.6">> TiddlyWiki also supports setting [[CSS custom properties|https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties]] as independent attributes. For example:
```
<div --bg-color={{{ [[red]] }}}>Hello</div>
```
{{Style Attributes}}
@@ -0,0 +1,29 @@
created: 20260821065249926
modified: 20260821065326363
tags: [[HTML in WikiText]] [[How to apply custom styles]]
title: Style Attributes
type: text/vnd.tiddlywiki
TiddlyWiki supports the usual HTML ''style'' attribute for assigning CSS styles to elements:
```
<div style="color:red;">Hello</div>
```
<<.from-version "5.2.2">> In an extension to HTML, TiddlyWiki also supports accessing individual CSS styles as independent attributes. For example:
```
<div style.color="red">Hello</div>
```
The advantage of this syntax is that it simplifies assigning computed values to CSS styles. For example:
```
<div style.color={{!!color}}>Hello</div>
```
<<.from-version "5.3.6">> TiddlyWiki also supports setting [[CSS custom properties|https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties]] as independent attributes. For example:
```
<div --bg-color={{{ [[red]] }}}>Hello</div>
```