Skip to content

Grid: horizontal cell spanning (per-row colSpan) — one cell covering several columns #17514

Description

@ENKOJanJungblut

Component / Area

Grid

Is your feature request related to a problem?

igx-grid can merge cells vertically (cellMergeMode, mergeStrategy, DefaultMergeStrategy), but a cell cannot span horizontally across several columns for a single row. There is no per-row colSpan and no full-width row template for data rows.

This is needed whenever a few rows in an otherwise regular table hold something wider than one column:

  • a row carrying a long free-text note or legal wording instead of its numeric values;
  • section, caption or footnote rows that are real data rows, not group-by rows;
  • "no data this period" / "carried forward" rows;
  • printed or regulatory tables that must match a paper form, where one row is a single wide cell.

The concept is plain colspan in an HTML table, and it exists in exported documents as well (Word and Excel table cells have a span), so a record that is stored and exported with a span cannot be displayed the way it is exported.

Without it, the only option is simulating the span in CSS against the grid's internal DOM, which leaves the grid's own model untouched: the collapsed cells still exist for keyboard navigation, cell selection, copy and export, so keyboard travel and exported output don't match what the user sees. Infragistics support confirmed that horizontal merging does not exist in igniteui-angular and that simulating it is currently the only option.

Describe the solution you'd like *

A per-row horizontal span, evaluated from the row data: a cell can declare that it covers N columns in that row, and the covered columns render no cell for that row — exactly like colspan in a plain table.

To be usable in a real grid, the span should be understood by the grid model and not only by the DOM:

  • navigation / selection — the spanning cell is one navigation stop and one cell for cell selection, range selection and copy;
  • virtualization — widths stay correct while columns scroll in and out horizontally;
  • column state — the span is expressed in columns and resolved against the currently visible column order, so pinning, hiding, resizing and moving keep working;
  • export — Excel maps it onto the columnSpan the exporter already models for header groups (IColumnInfo.columnSpan); CSV degrades to the single value;
  • editing — the spanning cell edits its own field; the covered fields are simply not editable in that row;
  • row height — a spanning cell with wrapped text grows the row, as rows already do today (row and cell heights are bound as min-height).

Describe the solution you'd like

A per-row horizontal span, evaluated from the row data — e.g. a callback on the column:

<igx-column field="note" [colSpan]="noteSpan"></igx-column>
// 1 (default), or the number of columns this cell covers in this row
public noteSpan = (rowData: MyRecord) => rowData.note != null ? 7 : 1;

Columns covered by the span render no cell for that row, exactly like colspan in a plain table.

Equally good alternatives, in decreasing order of effort:

  1. A grid-level configuration symmetric to the existing merging API — cellSpanMode plus a spanStrategy that returns the spans for a row, sitting next to cellMergeMode / mergeStrategy.
  2. A documented full-width row template with a predicate ("this row is one cell across all unpinned columns"), which would already cover the most common case.

To be usable in a real grid, the span should be understood by the grid model and not only by the DOM:

  • navigation / selection — the spanning cell is one navigation stop and one cell for cell selection, range selection and copy;
  • virtualization — widths stay correct while columns scroll in and out horizontally;
  • column state — the span is expressed in columns and resolved against the currently visible column order, so pinning, hiding, resizing and moving keep working;
  • export — Excel maps it onto the columnSpan the exporter already models for header groups (IColumnInfo.columnSpan); CSV degrades to the single value;
  • editing — the spanning cell edits its own field; the covered fields are simply not editable in that row.

Environment: igniteui-angular 20.1.5, Angular 20.3.18, flat igx-grid with a pinned action column.

Proposed API or Usage

Describe alternatives you've considered

  • Detail row (igxGridDetail) — renders an extra row below the record and brings in the expand indicator and expansion state. The wide content has to be the record's own row, so that selection, editing, row actions and export still see one row per record.

  • Group-by row — not a data row; it cannot carry the record's own values and row actions, and the records aren't grouped by that content.

  • Cell merging (cellMergeMode) — vertical only, and driven by equal adjacent values, so it cannot express a horizontal span.

  • Multi-row layout (igx-column-layout with colStart/colEnd) — spans are static per column definition, identical for every row; it cannot make the span depend on the record, and it changes the layout of the whole grid.

  • CSS simulation (what we use today). An igx-grid row is a flex container, so the narrow cells can be collapsed and the wide one grown into the freed space:

    ::ng-deep .igx-grid__tr:has(.wide-cell-marker) {
    
        .igx-grid__td:not(.igx-grid__td--pinned):not(:has(.wide-cell-marker)):not(:has(.keep-marker)) {
            display: none !important;
        }
    
        .igx-grid__td:has(.wide-cell-marker) {
            flex: 1 1 auto !important;
            width: auto !important;
            min-width: 0 !important;
            max-width: none !important;
        }
    }

    Marker classes have to be emitted from the cell templates, because a collapsed cell cannot otherwise be told apart from a genuinely empty one. It looks right, but: it depends on internal class names (igx-grid__tr, igx-grid__td, igx-grid__td--pinned) and on cells being flex items — implementation details that can change in any release; column widths are inline styles, so every override needs !important and ::ng-deep; navigation, selection, copy and export still see the collapsed cells; and it can only express "hide these, grow that one", never "span columns 2..8", so it breaks with two spanning blocks in one row or a span that must stop before the pinned columns.

How important is this feature to you?

Nice to have

Additional context

Existing API in the codebase that shows the shape being asked for, on the other axis or in other parts of the grid:

  • cellMergeMode / GridCellMergeMode / mergeStrategy / DefaultMergeStrategy — merging, but vertical only;
  • IColumnInfo.columnSpan — the exporter already models column spans for header groups;
  • colStart / colEnd / colSpan in the multi-row-layout internals and in the pivot grid's horizontal groups.

So the notion of a horizontal span already exists internally; what's missing is a public, per-row span for data cells.

If a full implementation is large, a supported and documented "one row, one full-width cell" template — with correct navigation, selection and export handling — would already cover the majority of these cases.

Environment: igniteui-angular 20.1.5, Angular 20.3.18, flat igx-grid with a pinned action column.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions