fix(bases): keep Task List groups collapsed on first render - #2166
Merged
callumalpass merged 3 commits intoAug 1, 2026
Merged
Conversation
A Task List view configured with defaultCollapsedState "Collapsed" seeds its collapsed-group sets during render. The debounced data-update render in BasesViewBase captures ephemeral state before that render and restores it in a finally block, so the pre-render (empty) snapshot overwrote the seed. Nothing re-seeded afterwards, because the group keys were already marked initialized. The result: the DOM still showed every group collapsed while the view's state said none were, so the first chevron click collapsed the clicked group and expanded all the others. Restore collapse state from ephemeral state only before the view has built its first grouping snapshot; afterwards the live sets are authoritative.
renatomen
marked this pull request as ready for review
July 29, 2026 00:40
renatomen
deleted the
fix/tasklist-collapsed-default-lost-on-first-render
branch
August 1, 2026 20:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Task List base view configured with Default collapsed state: Collapsed renders every group collapsed, but the first chevron click does the opposite of what you ask: the clicked group stays collapsed and every other group expands.
Root cause
The collapse default is seeded during render, then overwritten by a state snapshot captured before that render.
The first
render()returns early because Bases has not delivered data yet (the!this.data?.dataguard insrc/bases/TaskListView.ts).collapsedGroupsis still empty.Data arrives and
onDataUpdated()runs the debounced render wrapper insrc/bases/BasesViewBase.ts:That render seeds the collapse default through
initializeCollapseStateForSnapshotand paints the DOM all-collapsed.The
finallyreplacescollapsedGroupswith the stale empty array and does not re-render — so the DOM shows collapsed groups while the view's state says nothing is collapsed.The wipe is permanent: re-seeding is gated on
initializedPrimaryGroupKeys, which already holds every key, soinitializeCollapseStateForSnapshotnever seeds again.handleGroupTogglethen readscollapsedGroups.has(key) === falseand collapses the clicked group. The re-render expands all the others.Because the corruption needs the pre-render snapshot to be empty, this only bites on the first load of a view that has no previously saved collapse state — which is exactly the "starts collapsed" case.
Fix
Restore collapse state from ephemeral state only before the view has built its first grouping snapshot; afterwards the view's own sets are authoritative.
hasInitializedCollapseState()andrestoreCollapsedStateFromEphemeral()are extracted so the new guard is visible in review — the moved block is otherwise unchanged.Tests
Two regression tests in
tests/unit/ui/TaskListView.groupCollapse.test.tsreplay the ordering the render wrapper actually produces (seed, then restore a pre-render snapshot): one asserts the collapse default survives it, one asserts a toggle then expands only the clicked group.The suite already covered the opposite, safe ordering (restore-then-seed). The ordering production actually produces was untested, which is how this went unnoticed.
Verification
mainwithout the fix — with exactly the reported symptom — and pass with it.TZ=UTC.tsc --noEmitand eslint clean.Known trade-off
If
setEphemeralStateis ever called after the view's first render with collapse state worth applying, that portion is now ignored. The only caller I could find that runs post-render is the render wrapper's own save/restore round trip, which is the one we want ignored — but flagging it in case there is a path I missed.Note on the broader design
The underlying coupling remains:
get/setEphemeralStateserves both Obsidian's cross-reload persistence and an intra-render scroll round trip, so correctness depends on call ordering relative torender(). Separating those concerns inBasesViewBasewould eliminate the whole class of bug, but it touchesKanbanViewandCalendarView, which are not affected today. I kept it out of this change so the fix stays small and reviewable — happy to follow up if you would prefer that direction.