Skip to content

Sort Modes & Reordering

Tasks, Lists, and Steps have a persisted custom order (drag-and-drop) and an optional temporary sort chosen from a menu. Sorting produces a view order; drag-and-drop sets the persisted fractional rank (Product Brief §5.2 “Drag-and-drop / ordering rules”).

The pieces that turn a chosen mode into a rendered view order:

flowchart LR
  Menu["Sort menu (Tasks scope)"] --> Store["sort-mode-store.ts<br/>setSortMode / getSortMode"]
  Store --> Sub["subscribeSortMode(...)"]
  Sub --> Render["renderSortMode(items, mode)<br/>(sort-modes.ts)"]
  Store --> Default["defaultSortForView(view)"]
  Render --> Cmp["compareRanks(a, b)<br/>for custom order"]
  Render --> View["view order (rank never mutated)"]

src/lib/rank/sort-modes.tsrenderSortMode(items, mode) returns items in the chosen SortMode, using compareRanks for custom order. Per-scope modes (matching the scope sort policy):

  • Tasks: custom, alphabetical, due, created, importance.
  • Lists: custom, alphabetical, created.
  • Steps: custom, alphabetical, created.

Passing due/importance for Lists or Steps falls back to (rank, id) order. (Only the Tasks scope exposes the full sort dropdown; Lists and Steps reorder by drag-and-drop.)

How renderSortMode dispatches per mode, and how that relates to drag-and-drop writing rank:

flowchart TD
  Mode{SortMode?} -->|custom| Custom["sort by (rank, id)<br/>compareRanks"]
  Mode -->|alphabetical| Alpha["sort by title then id"]
  Mode -->|created| Created["sort by createdAt then id"]
  Mode -->|due| Due{"dueDate defined?<br/>(Tasks only)"}
  Mode -->|importance| Imp{"starred?<br/>(Tasks only)"}
  Due -->|no field| Fallback["fall back to (rank, id)"]
  Imp -->|no field| Fallback
  Custom --> View["view order (no rank write)"]
  Alpha --> View
  Created --> View
  Drag["drag-and-drop"] --> Rank["generateKeyBetween → persist rank"]

src/lib/prefs/sort-mode-store.ts keeps the active mode per scope instance (ScopeInstanceKey): getSortMode(...), setSortMode(scopeKey, mode), subscribeSortMode(...), and defaultSortForView(view) for the default per built-in View. The store is observable so sort menus and lists re-render on change.

Custom order is the fractional rank (per-List for Tasks, per-Task for Steps, per-User for Lists/Groups). Sorting never mutates rank; it only reorders the view. See the Fractional Rank Algorithm.

Related: Fractional Rank Algorithm, My Day & Owner-Scoped Views, List Sidebar & Drag-Drop (deferred guide).