Improve Narrow Options Table Responsiveness
Adapted the Options route for narrow screens so dense tape tables stay inside bounded panes, keep row identity visible while panning horizontally, and give the mobile ticker/filter controls more room to breathe.
Summary
The Options tape now behaves like a contained terminal pane on phone-sized screens instead of stretching down the page with the full virtual table height. The first table column remains pinned during horizontal panning, and the mobile topbar spacing is less compressed around the ticker field.
Changes Made
- Added bounded viewport-based heights for Options route panes at tablet and phone breakpoints.
- Kept the first table column sticky on narrow screens so row context remains visible while panning.
- Added a subtle right-edge affordance and touch scrolling refinements for horizontally wide tables.
- Improved mobile topbar and page-action spacing around the Menu, Ticker, Contract Filter, and Filter controls.
Context
The Options route contains high-density virtualized market data. On desktop, panes have bounded heights and table bodies scroll internally. At narrow breakpoints, the previous CSS changed those panes to automatic height, which made the table read as an endless page rather than an isolated tape viewport.
Important Implementation Details
- The fix stays CSS-only and preserves the existing virtualized row markup and row-height assumptions.
- The pane heights use
svhso mobile browser chrome is handled better than with classic viewport units. - The sticky first column is limited to the narrow-screen breakpoint where horizontal panning is expected.
- No backend URL or private environment configuration was added to committed source.
Relevant Diff Snippets
Rendered with @pierre/diffs/ssr using preloadPatchDiff against the real
apps/web/app/globals.css patch. The SSR output is embedded directly below.
146914701471147214731474248924902491249224932494256325642565256625672568256926152616261726182619262026212622262326242625263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667268526862687268826892690271627172718271927202721275327542755275627572758277027712772277327742775283228332834283528362837}.data-table-wrap {display: flex;flex: 1 1 auto;min-height: 0;min-height: 0;}.command-deck-grid {grid-template-columns: minmax(0, 1fr);grid-template-areas:}.terminal-content {padding: 16px 10px 22px;}.page-shell {position: sticky;top: 0;z-index: 30;padding: 12px 10px;}.terminal-topbar-leading {width: 100%;}.terminal-button,.terminal-topbar-actions,.terminal-topbar-controls,.terminal-topbar-mode {width: 100%;justify-content: flex-start;}.terminal-topbar-actions,.terminal-topbar-controls {flex-direction: column;align-items: stretch;}.terminal-menu-trigger {width: 100%;justify-content: center;}.terminal-topbar-mode .terminal-button,.terminal-topbar-controls > .terminal-button,.terminal-topbar-leading > .terminal-button,.page-actions > .terminal-button,.page-actions > .flow-filter-popover {width: 100%;}.instrument-focus-chip {max-width: none;min-height: 44px;justify-content: space-between;border-radius: 12px;}.terminal-pane-head,.terminal-pane-body {padding: 14px 12px;width: 100%;flex-direction: column;align-items: stretch;}.flow-filter-popover {margin-inline: -12px;border-radius: 0;scroll-snap-type: x proximity;}.data-table {padding-inline: 8px;}.data-table-row-options,.data-table-row-equities {height: 40px;}@media (max-width: 420px) {.terminal-content {padding-inline: 8px;}1469147014711472147314741475249024912492249324942495249624972498249925682569257025712572257325742620262126222623262426252626262726282629263026312632263326342635263626372638265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002718271927202721272227232724272527262727275327542755275627572758275927912792279327942795279627972798279928002801280228032804280528062807280828092821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592916291729182919292029212922292329242925292629272928292929302931293229332934293529362937}.data-table-wrap {position: relative;display: flex;flex: 1 1 auto;min-height: 0;min-height: 0;}.page-grid-options > .terminal-pane {height: clamp(430px, 68svh, 720px);}.command-deck-grid {grid-template-columns: minmax(0, 1fr);grid-template-areas:}.terminal-content {padding: 18px 10px calc(22px + env(safe-area-inset-bottom));}.page-shell {position: sticky;top: 0;z-index: 30;display: grid;grid-template-columns: minmax(0, 1fr) auto;align-items: start;column-gap: 10px;row-gap: 16px;padding: 10px 10px 12px;}.terminal-topbar-leading {width: auto;min-width: 0;grid-column: 1;grid-row: 1;}.terminal-button,.terminal-topbar-actions,.terminal-topbar-controls,.terminal-topbar-mode {min-width: 0;justify-content: flex-start;}.terminal-topbar-actions {display: contents;}.terminal-topbar-controls {width: 100%;grid-column: 1 / -1;grid-row: 2;display: grid;grid-template-columns: minmax(0, 1fr) auto;align-items: end;gap: 10px;}.terminal-topbar-mode {grid-column: 2;grid-row: 1;width: auto;justify-content: flex-end;}.terminal-menu-trigger {width: auto;justify-content: center;}.terminal-topbar-mode .terminal-button,.terminal-topbar-leading > .terminal-button,.page-actions > .terminal-button,.page-actions > .flow-filter-popover {width: 100%;}.terminal-topbar-controls > .terminal-button {width: auto;min-width: 76px;}.instrument-focus-chip {grid-column: 1 / -1;max-width: none;min-height: 44px;justify-content: space-between;border-radius: 12px;}.page-grid-options > .terminal-pane {height: clamp(390px, 62svh, 620px);}.terminal-pane-head,.terminal-pane-body {padding: 14px 12px;width: 100%;flex-direction: column;align-items: stretch;margin-top: 2px;}.flow-filter-popover {margin-inline: -12px;border-radius: 0;scroll-snap-type: x proximity;scrollbar-gutter: stable;overscroll-behavior-x: contain;-webkit-overflow-scrolling: touch;}.data-table-wrap::after {content: "";position: sticky;right: 0;z-index: 5;flex: 0 0 18px;pointer-events: none;background: linear-gradient(90deg, transparent, oklch(0.12 0.01 250 / 0.92));}.data-table {padding-inline: 8px;}.data-table-head .data-table-cell:first-child,.data-table-row .data-table-cell:first-child {position: sticky;left: 0;z-index: 4;margin-left: -8px;padding-left: 8px;background: oklch(0.13 0.01 250);box-shadow:1px 0 0 oklch(0.72 0.012 250 / 0.14),14px 0 18px oklch(0.06 0.01 250 / 0.42);}.data-table-head .data-table-cell:first-child {z-index: 6;background: oklch(0.15 0.012 250);}.data-table-row.is-even .data-table-cell:first-child {background: oklch(0.145 0.011 250);}.data-table-row:hover .data-table-cell:first-child,.data-table-row:focus-visible .data-table-cell:first-child {background: oklch(0.18 0.025 74);}.data-table-row-classified .data-table-cell:first-child {background:linear-gradient(90deg, rgba(var(--classifier-rgb, 192, 200, 210), calc(0.04 + var(--classifier-intensity, 0) * 0.1)), transparent 90%),oklch(0.13 0.01 250);}.data-table-row-options,.data-table-row-equities {height: 40px;}@media (max-width: 420px) {.terminal-topbar {column-gap: 8px;row-gap: 14px;padding-inline: 8px;}.terminal-menu-trigger {min-width: 92px;padding-inline: 8px;}.terminal-topbar-mode .terminal-button {min-width: 82px;padding-inline: 8px;}.terminal-content {padding-inline: 8px;}
Expected Impact for End-Users
On phones and narrow browser windows, traders can scan the Options tape inside a stable pane instead of losing the rest of the page to an unbounded table. Horizontal panning now keeps time context visible, and the top controls are easier to distinguish and tap.
Validation
- Passed:
bun --cwd=apps/web run build. - Passed: Browser check at 390px wide on
http://localhost:3000/options. - Measured a contained pane height of 523px and internal table viewport of 317px with a larger internal scroll height.
- Confirmed no page-level horizontal overflow and confirmed live tape status showed Connected.
Issues, Limitations, and Mitigations
- The narrow-screen table is still a dense data table, not a separate card/list representation.
- The sticky first column mitigates lost context without changing virtualization behavior or row heights.
- The page remains vertically scrollable between stacked panes, but each tape now owns its internal scroll.
Follow-up Work
No required follow-up is left for islandflow-833. A future enhancement could add a dedicated compact row layout for phone screens if the product wants less horizontal panning than the current dense terminal table.