plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

Description

@os-warren

Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

Symptom

The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

toolbar says January 2026 while the columns show late August

Cause

packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

<spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

The renderer already computes the right answer one row lower

Read from the DOM in the same frame as the screenshot:

elementvalue
toolbar period labelJanuary 2026
band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

Related, same toolbar: the two buttons beside the label are inert

The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

<Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

Reproduction

Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

  1. A gantt view over rows whose start dates run from January to December of the current year.
  2. Load it. The chart lands on Today.
  3. Toolbar reads the January label; the columns and the band header read the current month.

Suggested direction — maintainer's call, not proposed as decided

Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
     blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    
    Skip to content

    plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

    Description

    @os-warren

    Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

    Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

    Symptom

    The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

    toolbar says January 2026 while the columns show late August

    Cause

    packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

    <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

    timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

    The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

    The renderer already computes the right answer one row lower

    Read from the DOM in the same frame as the screenshot:

    elementvalue
    toolbar period labelJanuary 2026
    band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
    unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

    The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

    Related, same toolbar: the two buttons beside the label are inert

    The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

    <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

    So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

    Reproduction

    Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

    1. A gantt view over rows whose start dates run from January to December of the current year.
    2. Load it. The chart lands on Today.
    3. Toolbar reads the January label; the columns and the band header read the current month.

    Suggested direction — maintainer's call, not proposed as decided

    Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

    The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

    Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

    Metadata

    Metadata

    Assignees

    Labels

    bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
      Skip to content

      plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

      Description

      @os-warren

      Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

      Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

      Symptom

      The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

      toolbar says January 2026 while the columns show late August

      Cause

      packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

      <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

      timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

      The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

      The renderer already computes the right answer one row lower

      Read from the DOM in the same frame as the screenshot:

      elementvalue
      toolbar period labelJanuary 2026
      band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
      unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

      The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

      Related, same toolbar: the two buttons beside the label are inert

      The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

      <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

      So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

      Reproduction

      Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

      1. A gantt view over rows whose start dates run from January to December of the current year.
      2. Load it. The chart lands on Today.
      3. Toolbar reads the January label; the columns and the band header read the current month.

      Suggested direction — maintainer's call, not proposed as decided

      Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

      The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

      Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

      Metadata

      Metadata

      Assignees

      Labels

      bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

      Type

      No type

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
        Skip to content

        plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

        Description

        @os-warren

        Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

        Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

        Symptom

        The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

        toolbar says January 2026 while the columns show late August

        Cause

        packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

        <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

        timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

        The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

        The renderer already computes the right answer one row lower

        Read from the DOM in the same frame as the screenshot:

        elementvalue
        toolbar period labelJanuary 2026
        band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
        unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

        The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

        Related, same toolbar: the two buttons beside the label are inert

        The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

        <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

        So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

        Reproduction

        Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

        1. A gantt view over rows whose start dates run from January to December of the current year.
        2. Load it. The chart lands on Today.
        3. Toolbar reads the January label; the columns and the band header read the current month.

        Suggested direction — maintainer's call, not proposed as decided

        Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

        The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

        Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

        Metadata

        Metadata

        Assignees

        Labels

        bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
          Skip to content

          plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

          Description

          @os-warren

          Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

          Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

          Symptom

          The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

          toolbar says January 2026 while the columns show late August

          Cause

          packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

          <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

          timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

          The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

          The renderer already computes the right answer one row lower

          Read from the DOM in the same frame as the screenshot:

          elementvalue
          toolbar period labelJanuary 2026
          band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
          unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

          The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

          Related, same toolbar: the two buttons beside the label are inert

          The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

          <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

          So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

          Reproduction

          Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

          1. A gantt view over rows whose start dates run from January to December of the current year.
          2. Load it. The chart lands on Today.
          3. Toolbar reads the January label; the columns and the band header read the current month.

          Suggested direction — maintainer's call, not proposed as decided

          Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

          The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

          Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

          Metadata

          Metadata

          Assignees

          Labels

          bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

          Type

          No type

          Projects

          No projects

            Milestone

            No milestone

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
            Skip to content

            plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

            Description

            @os-warren

            Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

            Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

            Symptom

            The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

            toolbar says January 2026 while the columns show late August

            Cause

            packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

            <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

            timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

            The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

            The renderer already computes the right answer one row lower

            Read from the DOM in the same frame as the screenshot:

            elementvalue
            toolbar period labelJanuary 2026
            band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
            unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

            The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

            Related, same toolbar: the two buttons beside the label are inert

            The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

            <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

            So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

            Reproduction

            Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

            1. A gantt view over rows whose start dates run from January to December of the current year.
            2. Load it. The chart lands on Today.
            3. Toolbar reads the January label; the columns and the band header read the current month.

            Suggested direction — maintainer's call, not proposed as decided

            Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

            The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

            Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

            Metadata

            Metadata

            Assignees

            Labels

            bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

              Description

              @os-warren

              Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

              Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

              Symptom

              The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

              toolbar says January 2026 while the columns show late August

              Cause

              packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

              <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

              timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

              The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

              The renderer already computes the right answer one row lower

              Read from the DOM in the same frame as the screenshot:

              elementvalue
              toolbar period labelJanuary 2026
              band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
              unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

              The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

              Related, same toolbar: the two buttons beside the label are inert

              The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

              <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

              So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

              Reproduction

              Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

              1. A gantt view over rows whose start dates run from January to December of the current year.
              2. Load it. The chart lands on Today.
              3. Toolbar reads the January label; the columns and the band header read the current month.

              Suggested direction — maintainer's call, not proposed as decided

              Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

              The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

              Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

              Metadata

              Metadata

              Assignees

              Labels

              bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

              Type

              No type

              Projects

              No projects

                Milestone

                No milestone

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions

                , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                Skip to content

                plugin-gantt: the toolbar period label names the timeline RANGE START, not the visible window — it reads "January 2026" over columns showing late August, and the band header one row lower says "Aug 2026" #7203

                Description

                @os-warren

                Found in a browser pass over a real application's gantt view (objectstack-ai/duly#62). Filed unassigned, not claiming.

                Measured on @objectstack/console 17.2.0 (objectui 190fbd01d061) in Chromium 1194 at 1440x900. Re-checked against current main84ffdbcbb33762b5488742fb902faf45a3742e93: the expression below is unchanged there, so this is not a version-lag report.

                Symptom

                The toolbar reads January 2026 while the timeline underneath it shows 26 Aug through 6 Sep 2026, Today marker on 1 September.

                toolbar says January 2026 while the columns show late August

                Cause

                packages/plugin-gantt/src/GanttView.tsx — the toolbar span formats the range start:

                <spanclassName="font-semibold text-xs sm:text-sm">{timelineRange.start.toLocaleDateString(dateLocale,{month: 'long',year: 'numeric'})}</span>

                timelineRange is the memo that spans the whole dataset. With no startDate prop it resolves to min(task.start) minus 7 days, snapped to the period; the end is max(task.end) plus 14 days. So the label names the first month of the entire dataset, and it cannot change while the chart is scrolled because it is not derived from scroll position at all.

                The app in the screenshot holds tasks from 31 Jan to 31 Dec 2026, so this label sits on "January 2026" for every scroll position of an eleven-month timeline. On a first read it looks like the chart is showing January and the columns are mislabelled — the truth is the other way round.

                The renderer already computes the right answer one row lower

                Read from the DOM in the same frame as the screenshot:

                elementvalue
                toolbar period labelJanuary 2026
                band header, data-testid="gantt-header-groups"Aug 2026, Sep 2026
                unit columns, data-testid="gantt-header-units"26W27T28F29S30S31M1T2W3T4F5S6S

                The band header is already a viewport-derived month label and it contradicts the toolbar directly above it. Whatever the toolbar is meant to say, two month labels four pixels apart disagreeing is the part a user sees.

                Related, same toolbar: the two buttons beside the label are inert

                The prevPeriod / nextPeriod buttons render an aria-label and an icon and carry no onClick:

                <Buttonvariant="ghost"size="icon"className="h-8 w-8"aria-label={t('gantt.toolbar.prevPeriod')}><ChevronLeftclassName="h-4 w-4"/></Button>

                So the obvious recovery — "this says January, let me page forward to the month I am looking at" — does nothing, with no diagnostic. This is arguably the same defect: a period label and a pair of period-stepper buttons that are not wired to a period.

                Reproduction

                Any gantt whose dataset spans more than one month, scrolled anywhere other than its first month. The chart auto-scrolls to Today on load, so a dataset with history reproduces it on first paint with no interaction:

                1. A gantt view over rows whose start dates run from January to December of the current year.
                2. Load it. The chart lands on Today.
                3. Toolbar reads the January label; the columns and the band header read the current month.

                Suggested direction — maintainer's call, not proposed as decided

                Deriving the label from the visible window is the fix that makes the toolbar agree with the band header: the scroll offset already maps to a date (the pixel-to-date binary search used by the drag handlers), so the leftmost visible column's month is available without new state. The two stepper buttons then have something to drive — scroll by one unit of the current granularity.

                The alternative reading is that the label is meant to describe the whole range, in which case it should say so (a start-to-end range, not a single month) and the stepper buttons should go. Either way the current pairing cannot be right.

                Related: #7070 (gantt/timeline date-axis findings), #5132 (GanttViewMode doc line).

                Metadata

                Metadata

                Assignees

                Labels

                bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions