{"slug":"horizontal-scroll-table","meta":{"title":"Horizontal Scroll Table","slug":"horizontal-scroll-table","kind":"anti-pattern","summary":"Thirty columns pushed sideways off the screen because nobody decided which ones mattered — so half the data is hidden with no door and no indication it exists.","problem":"Every field became a column, the table no longer fits, and the fix was a horizontal scrollbar. Now the identifier scrolls away from the values, nothing can be compared, and the half of the data that is off-screen is not reliably the unimportant half.","family":["scan"],"principles":["progressive-disclosure","minimize-distance"],"status":"stable","visibility":"public","related":[{"title":"Dense Operational Table","url":"/patterns/dense-operational-table","summary":"The fix — a column budget, and everything else in the record."},{"title":"Progressive disclosure","url":"/patterns/progressive-disclosure","summary":"Why hiding with no visible door is the specific failure here."}]},"body":"## How you get here\n\nA horizontal scrollbar is what you reach for when the real decision — which\ncolumns earn their place — was never made. It is technically easy and it feels\ngenerous: nothing was removed, everything is still \"available\".\n\nThe reason it keeps happening is that adding a column has no visible cost to the\nperson requesting it, and removing one requires telling someone no.\n\n## Why it is worse than hiding\n\nEvery disclosure pattern hides something. The difference is the **door**.\n\n- A collapsed section has a labelled heading and a count.\n- A tab has a name and a number.\n- A drawer has a row you clicked.\n- A horizontal scroll has **nothing**. There is no indication of how many\n  columns exist, what they are, or that anything is off-screen at all.\n\nSo this is not a trade of visibility for density — it is hiding with no\naffordance, which is the classic progressive-disclosure mistake and the reason\nthe *invisible door* failure has its own name.\n\n## What it destroys\n\n- **Alignment.** A table's power is that a column shares an edge, so values\n  compare preattentively. Scrolled sideways, you can only see part of any column\n  at a time, and comparison across the set becomes impossible.\n- **Row identity.** Once the name column has scrolled away, you are reading\n  numbers with no idea whose they are. Freezing the first column patches this\n  and does not fix the rest.\n- **Trust in the default view.** People cannot tell whether the visible columns\n  are the important ones or just the first ones alphabetically. Usually they are\n  the first ones added.\n- **Every phone.** The pattern is unusable on a narrow screen, which is where\n  much operational work now happens.\n\n## The way out\n\n1. Apply the **column budget**: about six or seven. Identity, status, the one or\n   two comparable numbers, the owner, the driving date.\n2. Ask of every other column: *would anyone ever scan this column to decide\n   which row to open?* If not, it is detail, and detail belongs in the record.\n3. Put the rest behind a real door — a\n   [detail drawer](/patterns/master-detail-drawer), a record page, or\n   [collapsible sections](/patterns/collapsible-section).\n4. If different people genuinely need different columns, that is\n   [saved views](/patterns/saved-views), not one table with all of them.\n5. If the data genuinely is a wide grid people work across — a spreadsheet\n   replacement — then build a grid, with frozen headers and a frozen identifier\n   column, and know you are building a different product.\n\n## The tell\n\nAsk the people who use the screen to name the columns to the right of the fold.\nIf they cannot, those columns are not being read, and the scrollbar is\nprotecting a decision nobody wants to make.\n"}