Why Good Interfaces Think Like Spreadsheets and Tic-Tac-Toe Boards
Hatched by Honyee Chua
Jun 02, 2026
10 min read
1 views
78%
The hidden question behind every interactive UI
What is a user interface really? Most people would answer: a collection of buttons, panels, tables, charts, and forms. But that is only the surface. The deeper question is this: is your interface a place where data lives, or a place where data is merely reflected?
That distinction sounds abstract, but it determines whether a product feels coherent or chaotic. In one world, each piece of the interface keeps its own little secret, updating itself independently and hoping the rest of the screen stays in sync. In the other, the interface behaves like a well governed system: one source of truth, clear relationships, predictable updates, and the ability to reconstruct what happened. The difference is not cosmetic. It is the difference between a UI that scales gracefully and a UI that slowly turns into a tangle of surprises.
A simple game board and a data preview grid may seem unrelated. One is a toy problem, the other a serious tool for inspecting JSON, YAML, Parquet, spreadsheets, and large configuration files. Yet they are both solving the same core problem: how do you model change so the interface stays understandable? The answer, in both cases, is not to make things more clever. It is to make state legible, local where appropriate, shared where necessary, and always reconstructible.
The real unit of design is not the screen, it is the state boundary
A component is often introduced as reusable UI code, but that is too modest. A component is better understood as a boundary for responsibility. It does three things at once: it renders, it manages, and it updates a part of the interface. More importantly, it decides what information belongs inside and what information must be shared outside.
That boundary is where many UIs succeed or fail. If every square in a board keeps its own independent memory, the board becomes fragile. If every panel in a data preview tool keeps its own independent interpretation of the file, the experience becomes fragmented. You may still see the same data on screen, but you no longer have a coherent system. The user becomes the integrator, manually reconciling competing versions of reality.
This is why lifting state up is not merely a React pattern. It is a general design principle: when two children must agree, their shared truth belongs in the parent. In practical terms, that means the board remembers the squares, while each square receives its value as a prop. In a data grid, it means the rows, filters, pivots, and sort order should not each invent their own universe. They should derive from a shared model so the grid, the chart, and the export action all tell the same story.
Think of it like a spreadsheet. A formula cell does not maintain an alternate private version of the data. It depends on a shared sheet. That sharedness is what makes sorting, filtering, and charting possible without chaos. A UI with multiple views over the same data should feel like one sheet seen from different angles, not like multiple sheets pretending to be one.
The quality of an interface is often determined less by what it shows than by where it stores the truth.
Why immutability is really a memory system
The word immutability can sound ideological, as if the point is to avoid change. The opposite is true. Immutability is about making change intelligible. When you replace data with a new copy instead of mutating it in place, you preserve the old version as a reference point. That gives the system a memory of what used to be true, which is exactly what users need when they want undo, redo, comparison, or restoration after reload.
This is why a copy made with slice() matters more than it first appears. The copy is not just a technical workaround. It is a commitment to treating state as a sequence of explicit versions rather than an invisible puddle of mutable values. In a board game, that means every move can be reasoned about. In a data preview app, that means a filter, pivot, or chart transformation can be stored, restored, and even exported.
Consider the contrast between two mental models:
- Mutation as scrambling the same page: you erase and rewrite the same page repeatedly. It is efficient in the moment, but history disappears.
- Replacement as producing a new page: each edit creates a new page with a clear relationship to the previous one. History remains available.
The second model scales better because interactive systems are not just about showing the present. They are about supporting sequences of present moments. That is why undo and redo are not nice extras. They are proof that your interface has learned to respect time.
A data preview tool makes this especially concrete. If a user filters a huge JSON array, pivots a table, then switches to a chart, they are not performing isolated actions. They are building a chain of interpretation. When the settings persist across reloads, the app is saying something important: your analysis is not a fleeting gesture, it is a stateful argument. You should be able to return to it later and find the same shape of insight.
The most important function in UI design is not rendering, it is routing intent
Interactive systems often fail at the moment of action. A click should not mean “do whatever is easiest for the local widget.” It should mean “route this intent through the system in a way the system can understand.” That is why event handlers matter so much. When a square receives onSquareClick={() => handleClick(0)}, the function is not being executed immediately. It is being packaged as a future intention. The click does not directly mutate reality. It asks the system to process a request.
This matters because UI code is not merely about displaying values. It is about converting gestures into governed state transitions. Passing a callback down through props is a way of separating the act of clicking from the consequences of clicking. The button does not need to know the full game logic. The grid cell does not need to know the entire data pipeline. They need to know only how to report intent upward.
That separation is what keeps systems sane. A button in a React interface is both ordinary and special. Ordinary because it looks like any other element. Special because its onClick behavior has meaning to the browser and to the UI framework. Similarly, a chart in a data preview tool is not just an image. It is an expression of the current view state. Change the filter, and the chart should change. Change the pivot, and the chart should tell a different story. The chart is not a separate truth. It is a projection of the same truth.
A useful mental model here is the air traffic control tower. The planes do not negotiate their own landing order. They report position and intention to a central controller, which coordinates the system safely. That does not make the planes passive. It makes the whole operation comprehensible. In interface design, intent should flow upward, state should flow downward, and the user should experience the result as a consistent world rather than a collection of competing widgets.
From toy board to serious analytics: the same architecture, different stakes
The surprising connection between a game board and a data preview suite is that both are about state visibility under change. In a game, the challenge is to ensure that each move updates the board correctly, without accidental side effects. In a data tool, the challenge is to ensure that each transformation remains inspectable, restorable, and composable across many formats and views.
A board with independent square state can appear to work for a moment, but it is brittle. A data viewer with independent view state across tabs, charts, and exports can also appear to work, until the user asks for a crosscutting action like “save filtered data as CSV” or “restore this exact panel after restart.” Suddenly the hidden architecture becomes visible. If the app lacks a shared state model, it cannot answer those requests without awkward glue code.
This is where features like persistent settings, multi spreadsheet preview, summary display, pivoting, filtering, and exporting are not separate amenities. They are different faces of the same architectural requirement: the application must be able to narrate its own transformations. If the user can slice and dice a large dataset, then the app must remember what slice and what dice were used. If the user can chart filtered results, then the chart must derive from the same state that drove the grid. If the user can reopen a workspace, the app should reconstruct the view as if no time had passed.
That is the real power of a shared parent state. It is not about centralizing everything for its own sake. It is about enabling a system to remain internally consistent as it becomes more capable. Small apps can survive with loose coordination. Serious tools cannot. Once the number of views, operations, and file types grows, the architecture must become a memory system, not a collection of disconnected controls.
The more ways an interface can transform data, the more important it becomes that all transformations point back to the same source of truth.
A spreadsheet already understands this. So does a well designed analytics grid. A row filter, a chart, and a summary all depend on the same underlying values. That shared dependency is what makes the whole system feel responsive instead of random.
A practical framework: three questions for any interactive product
To design or evaluate an interface, ask three questions in order:
1. What is the source of truth?
Identify the smallest shared state that every relevant view must agree on. If two components need the same information, it probably does not belong privately inside either one. Put it higher, then pass it down as data.
2. What counts as an intent?
Separate user actions from state mutation. A click, filter change, pivot selection, or export request should first be captured as intent, then processed by the state holder. This prevents accidental coupling between presentation and logic.
3. What history must be recoverable?
If the user may want undo, redo, restore, compare, or persist settings across reloads, design state as versioned data rather than ephemeral mutation. Replace instead of overwrite. Save view configuration, not just current pixels.
This framework turns interface design from a collection of ad hoc choices into a structural discipline. It also clarifies when local state is appropriate. Not everything should be lifted. A transient hover effect or a temporary input draft may live comfortably inside a child. But when multiple parts of the system must coordinate, or when the action must survive time, the truth should move upward.
Key Takeaways
- Treat state as a shared contract, not a hidden detail. If multiple views must agree, store the truth once and derive the rest.
- Prefer replacement over mutation when the result must be explainable. New copies preserve history and make undo, redo, and persistence practical.
- Route user actions as intent, not direct side effects. Pass callbacks downward, process changes upward.
- Design for reconstruction, not just display. A good UI can restore itself after reload because it knows how it was built.
- Use the spreadsheet test. If a filter, chart, summary, and export cannot all describe the same data, the state model is probably too fragmented.
The interface as a memory of decisions
The deepest lesson here is that an interface is not just a surface for interaction. It is a memory of decisions. Every prop, every callback, every copied array, every preserved panel setting is part of a record of how the system came to its current shape. When that record is coherent, the user feels agency. When it is incoherent, the user feels like they are fighting the software.
That is why the best interactive systems feel calm even when they are powerful. They do not hide complexity. They organize it. They make state legible, change reversible, and relationships explicit. A tic tac toe board and a large data preview grid occupy different ends of the product spectrum, yet they both depend on the same profound idea: a good interface is a disciplined conversation between memory and change.
Once you see that, UI design stops looking like a problem of arranging boxes on a screen. It becomes a question of how a system remembers what matters, exposes it cleanly, and updates it without losing itself. And that, more than any visual flourish, is what makes software feel trustworthy.
Sources
Hatch New Ideas with Glasp AI 🐣
Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)
Start Hatching 🐣