Frontmatter
| id | 8964 |
| title | RFC: Component-Based Grid Rows (Neo.grid.Row) for Granular Updates |
| state | Closed |
| labels | enhancementepicaiarchitecture |
| assignees | tobiu |
| createdAt | Feb 3, 2026, 2:44 PM |
| updatedAt | Feb 4, 2026, 3:05 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8964 |
| author | tobiu |
| commentsCount | 3 |
| parentIssue | null |
| subIssues | 8965 feat: Create Neo.grid.Row component (#8964) 8966 refactor: Upgrade Neo.grid.Body to Container and implement Row Pooling (#8964) 8967 feat: Implement Reactive Record Updates in Neo.grid.Row (#8964) 8968 refactor: Migrate Component Columns to use Neo.grid.Row lifecycle (#8964) 8969 perf: Implement Batching and Silent Updates for Grid Scrolling (#8964) 8970 feat: Commit base implementation of Neo.grid.Row and refactored GridBody (#8964) 8971 fix: Enable horizontal scrolling by forcing Row VDOM updates on column mount change (#8964) 8973 fix: Component Columns disappear after horizontal scroll due to stale mounted state (#8964) 8974 refactor: Cleanup Neo.grid.Body and optimize Row/Body responsibilities (#8964) 8975 Fix Grid Header Drag Proxy for Row Component Architecture 8976 Fix Grid Cell Animations During Column Reordering 8977 Implement Surgical DOM Move for Component Columns in Drag Proxy 8978 Refactor Selection Models: Phase 1 (Base & Row) 8979 Refactor Selection Models: Phase 2 (Cell & Column) 8984 Fix Grid Row Reactivity & AnimatedChange Column for In-Place Updates 8985 refactor: Add getRow helper to GridBody 8986 docs: Knowledge Base Enhancement Strategy for Grid Classes (#8964) |
| subIssuesCompleted | 17 |
| subIssuesTotal | 17 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Feb 4, 2026, 3:05 PM |
RFC: Component-Based Grid Rows (Neo.grid.Row) for Granular Updates

Input from Gemini 3 Pro:
✦ Critical Architecture Note: Dynamic Column Handling & Performance
It is vital to clarify that
Neo.grid.Rowcannot effectively manage its own structure in isolation. A row's structure (cell order, visibility, renderers) is strictly dependent on theGrid.Container's column configuration, which is mutable at runtime.Responsibility: The
Grid.Body(orContainer) MUST remain the authority on defining the Row VDOM structure.Implementation Constraint: We must avoid a design where every
Neo.grid.Rowinstance independently listens to Grid events to rebuild itself. Instead, theGrid.Bodyshould efficiently orchestrate structural updates.Performance Optimization (Batching): When columns change (or during scrolling), updating 50+ row components individually could trigger significant traffic. Recommended pattern:
Grid.Bodyiterates over the Row pool.- Applies updates using
silentVdomUpdate: trueon each row to prevent immediate worker messages.- Triggers a single, consolidated update from the
Grid.Body(or utilizes theVdomUpdatemanager's batching capabilities explicitly) to flush all changes in one go. This ensures the Grid updates atomically, preventing "tearing" artifacts and minimizing IPC overhead.

Input from Gemini 3 Pro:
✦ I have analyzed the RFC and the codebase. This is a transformative refactor.
Here is the proposed breakdown of sub-tickets to tackle Epic #8964.
Phase 1: Foundation
1. Scaffold
Neo.grid.RowComponent
- Goal: Create the
Neo.grid.Rowclass.- Scope:
- Create
src/grid/Row.mjsextendingNeo.component.Base.- Migrate the cell rendering logic (HTML/Text cells) from
Body.createRowtoRow.mjs.- Define configs:
record,rowIndex,columns(passed from Body).- Deliverable: A Row component that can generate its own VDOM for standard cells.
2. Refactor
Neo.grid.Bodyto use Row Pooling
- Goal: Replace monolithic VDOM generation with a pool of Row components.
- Scope:
- Architectural Decision: Should
Neo.grid.Bodybe upgraded to extendNeo.container.Baseto natively handleitems? Or should we manually manage the lifecycle of Row components withinComponentto avoid Layout overhead? (RFC implies "standard items", suggestingContainer).- Implement
createRowPool(size)to instantiateNeo.grid.Rowinstances.- Update
createViewDataandupdateMountedAndVisibleRowsto recycle these instances (row.set({record, rowIndex})) instead of creating raw VDOM.- Deliverable: The Grid renders using
Neo.grid.Rowinstances.Phase 2: Reactivity & Features
3. Implement Granular Updates (Data Binding)
- Goal: Enable O(1) updates for single record changes.
- Scope:
- Refactor
Body.onStoreRecordChange.- Remove manual VDOM manipulation (
updateCellNode).- Logic: Find the matching
Rowinstance $\rightarrow$ callrow.set({record})$\rightarrow$ Row updates its own VDOM.- Deliverable: Editing a record updates only that Row's VDOM.
4. Migrate Component Columns (The "Zombie Canvas" Fix)
- Goal: Move component cell management to the Row.
- Scope:
- Refactor
Neo.grid.column.Component.- Move
cleanupComponentInstanceslogic from Body to Row.Rowautomatically instantiates/destroys cell components (like Sparklines) based on its state.- Deliverable: Sparklines/Widgets work inside the new Row architecture.
Phase 3: Optimization
5. Performance: Batching & Silent Updates
- Goal: Ensure scrolling performance matches or exceeds the current implementation.
- Scope:
- Implement
silentVdomUpdate: truefor Row updates during scroll.- Implement the batch flush in
Grid.Body(as noted in the RFC).- Benchmarking.

resolved.
Current Architecture
Currently,
Neo.grid.Bodyacts as a monolithic renderer. It manages a large VDOM structure representing all visible rows.createViewDataiterates through the store and generates a massive array of VDOM objects for rows and cells.onStoreRecordChange),grid.Bodyoften triggers a fullupdate(), sending the entire grid body VDOM to the worker (though diffing minimizes DOM ops, the serialization/transport cost is O(N)).grid.Bodymanually instantiates, updates, and destroys components (like Sparklines) within cells, managing their lifecycle via custom logic (cellRenderer,cleanupComponentInstances).The Proposal:
Neo.grid.RowRefactor the Grid to use a "Composed Architecture" where each row is a
Neo.component.Baseinstance.Core Concepts
Neo.grid.RowextendingNeo.component.Base.record,columns,rowIndex,gridContainer.afterSetRecordtriggers a VDOM update for only that row instance.Neo.grid.Bodymaintains a fixed pool ofNeo.grid.Rowinstances (based onavailableRows+ buffer).grid.Bodyupdates the configs of existing Row components (row.set({ record: newRecord, rowIndex: newIndex })).grid.Bodymanages these rows as standarditems.Benefits
Neo.grid.Rowinstance. The parentgrid.Bodydoes not need to re-render or diff the entire table.Rowcomponent. Their lifecycle (mount/unmount) is handled automatically by the framework's standard component tree logic, removing the fragile manual management ingrid.Body.grid.Bodymanages the viewport and scrolling.grid.Rowmanages the content and cell rendering.Challenges / Considerations
Neo.grid.Body,Neo.grid.column.Base(renderers might need adjustment), and CSS targeting (ensuringNeo.grid.Rowrenders the correct class/structure).Implementation Strategy
Neo.grid.Row: Create the class and ensure it can render a record given a set of columns.Neo.grid.Body:createRowVDOM generation.createRowPoolto instantiate components.onStoreRecordChangeto find the matching Row component and callset().Future Potential