-$button$
+\define lingo-base() $:/language/CloseAll/
+
+\define content()
+
-$droppable>
\end
+<$button message='tm-close-all-tiddlers' class='tc-btn-invisible tc-btn-mini'><
>$button>
diff --git a/core/wiki/config/DragnDrop.tid b/core/wiki/config/DragnDrop.tid
new file mode 100644
index 000000000..e9fb69082
--- /dev/null
+++ b/core/wiki/config/DragnDrop.tid
@@ -0,0 +1,3 @@
+title: $:/config/story/dragndrop/enable
+
+no
\ No newline at end of file
diff --git a/core/wiki/config/ShortcutInfo.multids b/core/wiki/config/ShortcutInfo.multids
index b2c843f35..0d0323bb3 100644
--- a/core/wiki/config/ShortcutInfo.multids
+++ b/core/wiki/config/ShortcutInfo.multids
@@ -44,6 +44,7 @@ stamp: {{$:/language/Buttons/Stamp/Hint}}
strikethrough: {{$:/language/Buttons/Strikethrough/Hint}}
subscript: {{$:/language/Buttons/Subscript/Hint}}
superscript: {{$:/language/Buttons/Superscript/Hint}}
+toggle-dragndrop: {{$:/language/Buttons/ToggleDragnDrop/Hint}}
toggle-sidebar: {{$:/language/Buttons/ToggleSidebar/Hint}}
transcludify: {{$:/language/Buttons/Transcludify/Hint}}
underline: {{$:/language/Buttons/Underline/Hint}}
diff --git a/core/wiki/config/shortcuts/shortcuts.multids b/core/wiki/config/shortcuts/shortcuts.multids
index 470988a9a..9a6c1fbd7 100644
--- a/core/wiki/config/shortcuts/shortcuts.multids
+++ b/core/wiki/config/shortcuts/shortcuts.multids
@@ -38,5 +38,6 @@ stamp: ctrl-S
strikethrough: ctrl-T
subscript: ctrl-shift-B
superscript: ctrl-shift-P
+toggle-dragndrop: alt-D
toggle-sidebar: alt-shift-S
transcludify: alt-shift-T
diff --git a/core/wiki/macros/dragndrop.tid b/core/wiki/macros/dragndrop.tid
new file mode 100644
index 000000000..e3afc3a4f
--- /dev/null
+++ b/core/wiki/macros/dragndrop.tid
@@ -0,0 +1,349 @@
+title: $:/core/wiki/macros/dragndrop
+tags: $:/tags/Global
+
+\procedure draggable-droppable-bottom-drag-enter-actions()
+<$action-setfield
+ $tiddler=<>
+ drag-count={{{ [get[drag-count]add[1]] }}}
+ drag-enter-class=<>
+/>
+<%if [has[drag-enter-count]] %>
+ <$action-setfield
+ $tiddler=<>
+ target-before=""
+ target-after={{{ [listafter] }}}
+ />
+ <$action-setfield
+ $tiddler=<>
+ start-next-tiddler=""
+ copy=""
+ target=<>
+ margin="bottom"
+ nth={{{ [listallbeforecount[]add[1]] }}}
+ next-tiddler=""
+ from-index={{{ [listallbeforecount[]add[1]] }}}
+ from-list=<>
+ drag-enter-count={{{ [get[drag-enter-count]add[1]] }}}
+ />
+<% else %>
+ <$action-setfield
+ $tiddler=<>
+ drag-enter-count="1"
+ />
+<% endif %>
+\end
+
+\procedure draggable-droppable-top-drag-enter-actions()
+<$action-setfield
+ $tiddler=<>
+ drag-count={{{ [get[drag-count]add[1]] }}}
+ drag-enter-class=<>
+/>
+<%if [has[drag-enter-count]] %>
+ <$action-setfield
+ $tiddler=<>
+ target-before={{{ [listbefore] }}}
+ target-after=""
+ />
+ <$action-setfield
+ $tiddler=<>
+ start-next-tiddler=""
+ copy=""
+ target=<>
+ margin="top"
+ nth={{{ [listallbeforecount[]] }}}
+ next-tiddler=""
+ from-index={{{ [listallbeforecount[]] }}}
+ from-list=<>
+ drag-enter-count={{{ [get[drag-enter-count]add[1]] }}}
+ />
+<% else %>
+ <$action-setfield
+ $tiddler=<>
+ drag-enter-count="1"
+ />
+<% endif %>
+\end
+
+\procedure draggable-droppable-bottom-drop-actions-inner()
+<$let
+ nextTiddler={{{ [listafter] }}}
+>
+ <%if [match[]] %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="[]"
+ />
+
+ <% else %>
+ <%if [!match] %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="+[insertbefore,]"
+ />
+
+ <% else %>
+ <$action-deletetiddler
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ />
+ <$action-deletetiddler
+ $tiddler=<>
+ />
+ <% endif %>
+ <% endif %>
+ <$action-deletetiddler
+ $tiddler=<>
+ />
+ <>
+$let>
+
+\end
+
+\procedure draggable-droppable-bottom-drop-actions()
+<$action-setfield
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ text="yes"
+/>
+<%if [removeprefixremovesuffix] %>
+ <$let
+ actionTiddler={{{ [removeprefixremovesuffix] }}}
+ >
+ <$transclude
+ $variable="draggable-droppable-bottom-drop-actions-inner"
+ />
+ $let>
+<% else %>
+ <$transclude
+ $variable="draggable-droppable-bottom-drop-actions-inner"
+ />
+<% endif %>
+<>
+\end
+
+\procedure draggable-droppable-top-drop-actions-inner()
+<%if [!match] %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="+[insertbefore,]"
+ />
+
+<% else %>
+ <$action-deletetiddler
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ />
+ <$action-deletetiddler
+ $tiddler=<>
+ />
+<% endif %>
+<$action-deletetiddler
+ $tiddler=<>
+/>
+
+\end
+
+\procedure draggable-droppable-top-drop-actions()
+<$action-setfield
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ text="yes"
+/>
+<%if [removeprefixremovesuffix] %>
+ <$let
+ actionTiddler={{{ [removeprefixremovesuffix] }}}
+ >
+ <$transclude
+ $variable="draggable-droppable-top-drop-actions-inner"
+ />
+ $let>
+<% else %>
+ <$transclude
+ $variable="draggable-droppable-top-drop-actions-inner"
+ />
+<% endif %>
+\end
+
+\procedure draggable-droppable-drag-end-actions()
+<%if [addsuffix[/drag-handled]is[missing]] %>
+ <$let
+ fromList={{{ [get[start-from-list]] }}}
+ fromIndex={{{ [get[start-from-index]] }}}
+ listBeforeTiddler={{{ [listzth] }}}
+ actionTiddler={{{ [removeprefixremovesuffix] :else[] }}}
+ >
+ <%if [!is[blank]] %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="+[insertbefore,]"
+ />
+ <% else %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="[]"
+ />
+ <% endif %>
+ <$action-deletetiddler
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ />
+ <$action-deletetiddler
+ $tiddler=<>
+ />
+ $let>
+<% else %>
+ <$action-deletetiddler
+ $tiddler={{{ [addsuffix[/drag-handled]] }}}
+ />
+<% endif %>
+\end
+
+\procedure draggable-droppable-drag-start-actions()
+<$let
+ nth={{{ [listallbeforecount[]] }}}
+ listLength={{{ [listcount[]subtract[1]] }}}
+>
+ <%if [match] %>
+ <$action-setfield
+ $tiddler=<>
+ before-tiddler={{{ [listbefore] }}}
+ />
+ <% endif %>
+ <$action-setfield
+ $tiddler=<>
+ drag-count="0"
+ nth=<>
+ height=<>
+ width=<>
+ margin-bottom=<>
+ start-next-tiddler={{{ [listafter] }}}
+ start-from-index={{{ [listallbeforecount[]] }}}
+ start-from-list=<>
+ />
+ <$action-setfield
+ $tiddler=<>
+ drag-tiddler=<>
+ next-tiddler={{{ [listafter] }}}
+ from-index={{{ [listallbeforecount[]] }}}
+ from-list=<>
+ from-history=<>
+ target={{{ [listafter] }}}
+ />
+ <$action-setfield
+ $tiddler=<>
+ tags="$:/tags/DragStateTiddler"
+ text="yes"
+ />
+ <%if [!match[ctrl]] %>
+ <$action-listops
+ $tiddler=<>
+ $subfilter="-[]"
+ />
+ <% else %>
+ <$action-setfield
+ $tiddler=<>
+ copy="yes"
+ />
+ <% endif %>
+$let>
+\end
+
+\function get.drag.state.tiddler.height() [get[height]addsuffix[px]]
+\function get.drag.state.tiddler.margin.bottom() [get[margin-bottom]]
+
+\function get.draggable.droppable.bottom.class() tc-draggable-droppable-drop-bottom [get[margin]match[bottom]then] :and[join[ ]]
+\function get.draggable.droppable.top.class() tc-draggable-droppable-drop-top [get[margin]match[top]then] :and[join[ ]]
+
+\function get.tiddler.before.target() [get[target]] :reduce[listbefore]
+\function get.tiddler.after.target() [get[target]] :reduce[listafter]
+
+\function get.styleTransition()
+ [get[start-next-tiddler]matchthen[none]]
+ :else[[margin-top ]addsuffixaddsuffix[ms ]addsuffixaddsuffix[, margin-bottom ]addsuffixaddsuffix[ms ]addsuffix]
+\end
+
+\function get.styleTop() [get[start-next-tiddler]matchthen[calc(-]addsuffixaddsuffix[ - (2 * ]addsuffixaddsuffix[)]] :else[get[drag-enter-class]matchthenget[margin]match[top]then[calc(-]addsuffixaddsuffix[ - (2 * ]addsuffixaddsuffix[)]] :else[[calc( ]addsuffix[-]addsuffixaddsuffix[)]]
+
+\function get.styleBottom() [[calc( ]addsuffix[-]addsuffixaddsuffix[)]]
+\function get.styleLeft() [[calc( ]addsuffix[-]addsuffixaddsuffix[)]]
+
+\function get.styleTopHeight() [get[start-next-tiddler]matchthen[calc(50% + ]addsuffixaddsuffix[ + ]addsuffixaddsuffix[)]] :else[get[drag-enter-class]matchthenget[margin]match[top]then[calc(50% + (2 * ]addsuffixaddsuffix[) + ]addsuffixaddsuffix[)]] :else[[calc(50% + ]addsuffixaddsuffix[)]]
+
+\function get.styleBottomHeight() [get[drag-enter-class]matchthenget[margin]match[bottom]then[calc(50% + ]addsuffixaddsuffix[ + ]addsuffixaddsuffix[)]] :else[[50%]]
+
+\function get.styleWidth() [[calc(100% + ]addsuffixaddsuffix[ + ]addsuffixaddsuffix[)]]
+
+\function get.styleMarginTop() [get[start-next-tiddler]matchthen[calc(]addsuffixaddsuffix[ + (2 * ]addsuffixaddsuffix[))]] :else[get[drag-enter-class]matchthenget[margin]match[top]thenget[height]addsuffix[px]addprefix[calc(]addsuffix[ + (2 * ]addsuffixaddsuffix[))]] :else[[0px]]
+\function get.styleMarginBottom() [get[drag-enter-class]matchthenget[margin]match[bottom]thenget[height]addsuffix[px]addprefix[calc(]addsuffix[ + (2 * ]addsuffixaddsuffix[))]] :else[[0px]]
+
+\function get.draggable.droppable.class() tc-draggable-droppable-qualifier [] :and[join[ ]]
+\function get.flexDirection() [match[vertical]then[row]] [match[horizontal]then[column]]
+
+\procedure make-draggable-droppable(tiddler:"",class:"",content:"",list:"",enable:"yes",dropActions:"",history:"",dragStateTiddler:"$:/state/tiddlywiki/dragging",direction:"vertical",styleMarginTop:"0px",styleMarginBottom:"0px",stylePaddingLeft:"0px",stylePaddingRight:"0px",styleZIndex:"501",animationDuration:"175",animationCurve:"linear")
+\whitespace trim
+<$tiddler tiddler=<>>
+<$let
+ prefix="[["
+ suffix="]]"
+ transclusion=<>
+ qualifiedDragEnterClass={{{ [addsuffixsha256[64]] }}}
+>
+ <$draggable
+ enable=<>
+ tiddler=<>
+ startactions=<>
+ endactions=<>
+ class=<>
+ >
+ >
+ style.display="flex"
+ style.position="relative"
+ style.flex-direction=<
>
+ style.border="none"
+ style.margin-top=<>
+ style.margin-bottom=<>
+ style.transition=<>
+ >
+ <$set name="tv-enable-drag-and-drop" value={{{ [match[yes]then[no]] :else[] }}}>
+ <>
+ $set>
+ <%if [get[text]match[yes]] %>
+ <%if [match[vertical]] %>
+ <$droppable
+ class=<>
+ actions=<>
+ dragenteractions=<>
+ >
+ >
+ style.left=<
>
+ style.height=<>
+ style.width=<>
+ style.z-index=<>
+ />
+ $droppable>
+ <$droppable
+ class=<>
+ actions=<>
+ dragenteractions=<>
+ >
+ >
+ style.height=<>
+ style.width=<>
+ style.z-index=<>
+ />
+ $droppable>
+ <%elseif [match[horizontal]] %>
+
+ <% endif %>
+ <% endif %>
+
+ $draggable>
+$let>
+$tiddler>
+\end
diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9507 - dragndrop.tid b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9507 - dragndrop.tid
new file mode 100644
index 000000000..feb447a32
--- /dev/null
+++ b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9507 - dragndrop.tid
@@ -0,0 +1,15 @@
+title: $:/changenotes/5.4.0/#9507
+created: 20251218204100502
+modified: 20251218204100502
+tags: $:/tags/ChangeNote
+change-type: enhancement
+change-category: usability
+description: Dragndrop procedures for enhanced dragndrop lists
+release: 5.4.0
+github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9507
+github-contributors: BurningTreeC
+type: text/vnd.tiddlywiki
+
+This pull request extends Tiddlywiki with advanced drag-and-drop procedures.
+
+Lists can be expanded using drag-and-drop, and the drag-and-drop experience feels more natural.