# Selection > Row, column, and range selection modes and behaviors. --- .. llms_copy::references/selection .. toc:: ### Overview Dash Glide Grid supports flexible selection modes for cells, rows, columns, and ranges. Configure how selections interact using blending modes. ### Basic Usage Track the currently selected cell using the `selectedCell` callback prop. .. exec::examples.reference.selection.basic :code: false ```python # File: examples/reference/selection/basic.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Email", "id": "email", "width": 200}, {"title": "Role", "id": "role", "width": 120}, {"title": "Status", "id": "status", "width": 100}, ] data = [ {"name": "Alice Johnson", "email": "alice@example.com", "role": "Engineer", "status": "Active"}, {"name": "Bob Smith", "email": "bob@example.com", "role": "Designer", "status": "Active"}, {"name": "Carol White", "email": "carol@example.com", "role": "Manager", "status": "Away"}, {"name": "David Brown", "email": "david@example.com", "role": "Developer", "status": "Active"}, ] component = dmc.Stack([ dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-basic"}, columns=columns, data=data, height=200, ), dmc.Text(id="selection-basic-output", size="sm", c="dimmed"), ]) @callback( Output("selection-basic-output", "children"), Input({"type": "glide-grid", "index": "selection-basic"}, "selectedCell"), ) def show_selected_cell(cell): if cell: return f"Selected cell: column {cell['col']}, row {cell['row']}" return "Click a cell to select it" ``` :defaultExpanded: false :withExpandedButton: true ### Row Selection Enable row selection with `rowSelect`. Use `rowSelectionMode` to control modifier key behavior. .. exec::examples.reference.selection.rows :code: false ```python # File: examples/reference/selection/rows.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Department", "id": "dept", "width": 120}, {"title": "Salary", "id": "salary", "width": 100}, {"title": "Status", "id": "status", "width": 100}, ] data = [ {"name": "Alice Johnson", "dept": "Engineering", "salary": 95000, "status": "Active"}, {"name": "Bob Smith", "dept": "Marketing", "salary": 72000, "status": "Active"}, {"name": "Carol White", "dept": "Engineering", "salary": 88000, "status": "Away"}, {"name": "David Brown", "dept": "Sales", "salary": 65000, "status": "Inactive"}, {"name": "Eve Davis", "dept": "HR", "salary": 70000, "status": "Active"}, ] component = dmc.Stack([ dmc.Group([ dmc.Select( id="selection-rows-mode", label="Row Select", data=[ {"value": "none", "label": "None"}, {"value": "single", "label": "Single"}, {"value": "multi", "label": "Multi"}, ], value="multi", w=120, ), dmc.Select( id="selection-rows-selection-mode", label="Selection Mode", data=[ {"value": "auto", "label": "Auto (Ctrl/Cmd)"}, {"value": "multi", "label": "Multi (No modifier)"}, ], value="auto", w=160, ), ]), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-rows"}, columns=columns, data=data, height=220, rowMarkers="checkbox-visible", rowSelect="multi", rowSelectionMode="auto", ), dmc.Text(id="selection-rows-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-rows"}, "rowSelect"), Input("selection-rows-mode", "value"), ) def update_row_select(value): return value @callback( Output({"type": "glide-grid", "index": "selection-rows"}, "rowSelectionMode"), Input("selection-rows-selection-mode", "value"), ) def update_selection_mode(value): return value @callback( Output("selection-rows-output", "children"), Input({"type": "glide-grid", "index": "selection-rows"}, "selectedRows"), ) def show_selection(rows): if rows: return f"Selected rows: {rows}" return "Click row markers to select rows" ``` :defaultExpanded: false :withExpandedButton: true ### Column Selection Enable column selection with `columnSelect`. Use `columnSelectionMode` to control modifier key behavior. Click column headers to select entire columns. .. exec::examples.reference.selection.columns :code: false ```python # File: examples/reference/selection/columns.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Email", "id": "email", "width": 200}, {"title": "Role", "id": "role", "width": 120}, {"title": "Department", "id": "department", "width": 130}, {"title": "Status", "id": "status", "width": 100}, ] data = [ {"name": "Alice Johnson", "email": "alice@example.com", "role": "Engineer", "department": "Engineering", "status": "Active"}, {"name": "Bob Smith", "email": "bob@example.com", "role": "Designer", "department": "Design", "status": "Active"}, {"name": "Carol White", "email": "carol@example.com", "role": "Manager", "department": "Marketing", "status": "Away"}, {"name": "David Brown", "email": "david@example.com", "role": "Developer", "department": "Engineering", "status": "Active"}, ] component = dmc.Stack([ dmc.Group([ dmc.Select( id="selection-columns-mode", label="Column Select", data=[ {"value": "none", "label": "None"}, {"value": "single", "label": "Single"}, {"value": "multi", "label": "Multi"}, ], value="multi", w=120, ), dmc.Select( id="selection-columns-selection-mode", label="Selection Mode", data=[ {"value": "auto", "label": "Auto (Ctrl/Cmd)"}, {"value": "multi", "label": "Multi (No modifier)"}, ], value="auto", w=160, ), ]), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-columns"}, columns=columns, data=data, height=200, columnSelect="multi", columnSelectionMode="auto", ), dmc.Text(id="selection-columns-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-columns"}, "columnSelect"), Input("selection-columns-mode", "value"), ) def update_column_select(value): return value or "none" @callback( Output({"type": "glide-grid", "index": "selection-columns"}, "columnSelectionMode"), Input("selection-columns-selection-mode", "value"), ) def update_selection_mode(value): return value @callback( Output("selection-columns-output", "children"), Input({"type": "glide-grid", "index": "selection-columns"}, "selectedColumns"), ) def display_selected_columns(selected): if selected: return f"Selected columns: {selected}" return "Click column headers to select columns" ``` :defaultExpanded: false :withExpandedButton: true ### Range Selection Use `rangeSelect` to enable rectangular selections. Modes include single cell, single rect, or multiple selections. .. exec::examples.reference.selection.ranges :code: false ```python # File: examples/reference/selection/ranges.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Q1", "id": "q1", "width": 80}, {"title": "Q2", "id": "q2", "width": 80}, {"title": "Q3", "id": "q3", "width": 80}, {"title": "Q4", "id": "q4", "width": 80}, ] data = [ {"name": "Product A", "q1": 1200, "q2": 1350, "q3": 1400, "q4": 1550}, {"name": "Product B", "q1": 800, "q2": 920, "q3": 1050, "q4": 1100}, {"name": "Product C", "q1": 2100, "q2": 2300, "q3": 2150, "q4": 2400}, {"name": "Product D", "q1": 650, "q2": 700, "q3": 680, "q4": 720}, {"name": "Product E", "q1": 1800, "q2": 1750, "q3": 1900, "q4": 2000}, ] component = dmc.Stack([ dmc.Select( id="selection-ranges-mode", label="Range Select", data=[ {"value": "none", "label": "None"}, {"value": "cell", "label": "Cell (single cell)"}, {"value": "rect", "label": "Rect (single range)"}, {"value": "multi-cell", "label": "Multi-Cell"}, {"value": "multi-rect", "label": "Multi-Rect"}, ], value="rect", w=180, ), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-ranges"}, columns=columns, data=data, height=220, rangeSelect="rect", ), dmc.Text(id="selection-ranges-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-ranges"}, "rangeSelect"), Input("selection-ranges-mode", "value"), ) def update_range_select(value): return value @callback( Output("selection-ranges-output", "children"), Input({"type": "glide-grid", "index": "selection-ranges"}, "selectedRange"), Input({"type": "glide-grid", "index": "selection-ranges"}, "selectedRanges"), ) def show_range(primary_range, additional_ranges): parts = [] if primary_range: parts.append( f"Range: ({primary_range['startCol']}, {primary_range['startRow']}) " f"to ({primary_range['endCol']}, {primary_range['endRow']})" ) if additional_ranges: parts.append(f"Additional ranges: {len(additional_ranges)}") return " | ".join(parts) if parts else "Click and drag to select a range" ``` :defaultExpanded: false :withExpandedButton: true ### Selection Blending Control how different selection types interact. Use `exclusive` to clear other selections or `mixed` to allow them to coexist. .. exec::examples.reference.selection.blending :code: false ```python # File: examples/reference/selection/blending.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Department", "id": "dept", "width": 120}, {"title": "Role", "id": "role", "width": 120}, {"title": "Status", "id": "status", "width": 100}, ] data = [ {"name": "Alice Johnson", "dept": "Engineering", "role": "Engineer", "status": "Active"}, {"name": "Bob Smith", "dept": "Marketing", "role": "Designer", "status": "Active"}, {"name": "Carol White", "dept": "Engineering", "role": "Manager", "status": "Away"}, {"name": "David Brown", "dept": "Sales", "role": "Developer", "status": "Active"}, {"name": "Eve Davis", "dept": "HR", "role": "Analyst", "status": "Active"}, ] component = dmc.Stack([ dmc.Group([ dmc.Select( id="selection-blending-row", label="Row Blending", data=[ {"value": "exclusive", "label": "Exclusive"}, {"value": "mixed", "label": "Mixed"}, ], value="mixed", w=130, ), dmc.Select( id="selection-blending-column", label="Column Blending", data=[ {"value": "exclusive", "label": "Exclusive"}, {"value": "mixed", "label": "Mixed"}, ], value="mixed", w=130, ), dmc.Select( id="selection-blending-range", label="Range Blending", data=[ {"value": "exclusive", "label": "Exclusive"}, {"value": "mixed", "label": "Mixed"}, ], value="mixed", w=130, ), ]), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-blending"}, columns=columns, data=data, height=220, rowMarkers="checkbox-visible", rowSelect="multi", columnSelect="multi", rangeSelect="rect", rowSelectionBlending="mixed", columnSelectionBlending="mixed", rangeSelectionBlending="mixed", ), dmc.Text(id="selection-blending-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-blending"}, "rowSelectionBlending"), Input("selection-blending-row", "value"), ) def update_row_blending(value): return value @callback( Output({"type": "glide-grid", "index": "selection-blending"}, "columnSelectionBlending"), Input("selection-blending-column", "value"), ) def update_column_blending(value): return value @callback( Output({"type": "glide-grid", "index": "selection-blending"}, "rangeSelectionBlending"), Input("selection-blending-range", "value"), ) def update_range_blending(value): return value @callback( Output("selection-blending-output", "children"), Input({"type": "glide-grid", "index": "selection-blending"}, "selectedRows"), Input({"type": "glide-grid", "index": "selection-blending"}, "selectedColumns"), Input({"type": "glide-grid", "index": "selection-blending"}, "selectedRange"), ) def show_selections(rows, columns, range_sel): parts = [] if rows: parts.append(f"Rows: {rows}") if columns: parts.append(f"Columns: {columns}") if range_sel: parts.append(f"Range: ({range_sel['startCol']},{range_sel['startRow']})-({range_sel['endCol']},{range_sel['endRow']})") return " | ".join(parts) if parts else "Try selecting rows, columns, and ranges together" ``` :defaultExpanded: false :withExpandedButton: true ### Selection Constraints [dgg] Prevent selection of specific rows or columns with `unselectableRows` and `unselectableColumns`. .. exec::examples.reference.selection.constraints :code: false ```python # File: examples/reference/selection/constraints.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "ID", "id": "id", "width": 60}, {"title": "Name", "id": "name", "width": 150}, {"title": "Email", "id": "email", "width": 200}, {"title": "Role", "id": "role", "width": 120}, ] data = [ {"id": 1, "name": "Alice Johnson", "email": "alice@example.com", "role": "Engineer"}, {"id": 2, "name": "Bob Smith", "email": "bob@example.com", "role": "Designer"}, {"id": 3, "name": "Carol White", "email": "carol@example.com", "role": "Manager"}, {"id": 4, "name": "David Brown", "email": "david@example.com", "role": "Developer"}, {"id": 5, "name": "Eve Davis", "email": "eve@example.com", "role": "Analyst"}, ] component = dmc.Stack([ dmc.Group([ dmc.MultiSelect( id="selection-constraints-rows", label="Unselectable Rows", data=[{"value": str(i), "label": f"Row {i}"} for i in range(5)], value=["0"], w=180, ), dmc.MultiSelect( id="selection-constraints-cols", label="Unselectable Columns", data=[{"value": str(i), "label": col["title"]} for i, col in enumerate(columns)], value=["0"], w=180, ), ]), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-constraints"}, columns=columns, data=data, height=220, rowMarkers="checkbox-visible", rowSelect="multi", columnSelect="multi", rangeSelect="rect", unselectableRows=[0], unselectableColumns=[0], ), dmc.Text(id="selection-constraints-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-constraints"}, "unselectableRows"), Input("selection-constraints-rows", "value"), ) def update_unselectable_rows(values): return [int(v) for v in values] if values else [] @callback( Output({"type": "glide-grid", "index": "selection-constraints"}, "unselectableColumns"), Input("selection-constraints-cols", "value"), ) def update_unselectable_cols(values): return [int(v) for v in values] if values else [] @callback( Output("selection-constraints-output", "children"), Input({"type": "glide-grid", "index": "selection-constraints"}, "selectedRows"), Input({"type": "glide-grid", "index": "selection-constraints"}, "selectedColumns"), Input("selection-constraints-rows", "value"), Input("selection-constraints-cols", "value"), ) def show_selections(rows, cols, unselectable_rows, unselectable_cols): parts = [] if rows: parts.append(f"Selected rows: {rows}") if cols: parts.append(f"Selected columns: {cols}") if not parts: blocked = [] if unselectable_rows: blocked.append(f"rows {unselectable_rows}") if unselectable_cols: blocked.append(f"columns {unselectable_cols}") if blocked: return f"Cannot select {' and '.join(blocked)}" return "No constraints set" return " | ".join(parts) ``` :defaultExpanded: false :withExpandedButton: true ### Range Selection Column Spanning Control whether range selections can span across multiple columns with `rangeSelectionColumnSpanning`. When disabled, drag selections are restricted to a single column. .. exec::examples.reference.selection.column_spanning :code: false ```python # File: examples/reference/selection/column_spanning.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "A", "id": "a", "width": 70}, {"title": "B", "id": "b", "width": 70}, {"title": "C", "id": "c", "width": 70}, {"title": "D", "id": "d", "width": 70}, {"title": "E", "id": "e", "width": 70}, {"title": "F", "id": "f", "width": 70}, ] data = [ {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6}, {"a": 7, "b": 8, "c": 9, "d": 10, "e": 11, "f": 12}, {"a": 13, "b": 14, "c": 15, "d": 16, "e": 17, "f": 18}, {"a": 19, "b": 20, "c": 21, "d": 22, "e": 23, "f": 24}, {"a": 25, "b": 26, "c": 27, "d": 28, "e": 29, "f": 30}, ] component = dmc.Stack([ dmc.Switch( id="selection-spanning-toggle", label="Range Selection Column Spanning", checked=True, ), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-spanning"}, columns=columns, data=data, height=220, rangeSelectionColumnSpanning=True, ), dmc.Text(id="selection-spanning-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-spanning"}, "rangeSelectionColumnSpanning"), Input("selection-spanning-toggle", "checked"), ) def update_spanning(checked): return checked @callback( Output("selection-spanning-output", "children"), Input({"type": "glide-grid", "index": "selection-spanning"}, "selectedRange"), Input("selection-spanning-toggle", "checked"), ) def show_range(selected_range, spanning_enabled): if selected_range: cols = selected_range["endCol"] - selected_range["startCol"] + 1 rows = selected_range["endRow"] - selected_range["startRow"] + 1 return f"Selected: {cols} col(s) x {rows} row(s)" if spanning_enabled: return "Click and drag to select across multiple columns" return "Spanning disabled: selection restricted to single column" ``` :defaultExpanded: false :withExpandedButton: true ### Trap Focus Prevent keyboard focus from leaving the grid with `trapFocus`. When enabled, Tab and arrow keys keep focus within the grid. Useful for modal-like interfaces or full-screen grid applications. .. exec::examples.reference.selection.trap_focus :code: false ```python # File: examples/reference/selection/trap_focus.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Value", "id": "value", "width": 100}, {"title": "Notes", "id": "notes", "width": 200}, ] data = [ {"name": "Item A", "value": 100, "notes": "Try Tab to leave grid"}, {"name": "Item B", "value": 200, "notes": "With trap, Tab stays in"}, {"name": "Item C", "value": 300, "notes": "Arrow keys also trapped"}, {"name": "Item D", "value": 400, "notes": "Click outside to release"}, ] component = dmc.Stack([ dmc.Switch( id="selection-trap-toggle", label="Trap Focus", checked=False, ), dgg.GlideGrid( id={"type": "glide-grid", "index": "selection-trap"}, columns=columns, data=data, height=200, trapFocus=False, ), dmc.Text(id="selection-trap-output", size="sm", c="dimmed"), ]) @callback( Output({"type": "glide-grid", "index": "selection-trap"}, "trapFocus"), Input("selection-trap-toggle", "checked"), ) def update_trap(checked): return checked @callback( Output("selection-trap-output", "children"), Input("selection-trap-toggle", "checked"), ) def show_description(trapped): if trapped: return "Focus trapped: Tab and arrow keys stay within grid" return "Normal navigation: Tab moves to next element" ``` :defaultExpanded: false :withExpandedButton: true ### Props Reference #### Selection Mode Props | Property | Type | Default | Description | |----------|------|---------|-------------| | `rowSelect` | string | 'none' | Row selection: 'none', 'single', 'multi' | | `columnSelect` | string | 'none' | Column selection: 'none', 'single', 'multi' | | `rangeSelect` | string | 'rect' | Range selection: 'none', 'cell', 'rect', 'multi-cell', 'multi-rect' | | `rowSelectionMode` | string | 'auto' | 'auto' (requires Ctrl/Cmd) or 'multi' (no modifier) | | `columnSelectionMode` | string | 'auto' | 'auto' (requires Ctrl/Cmd) or 'multi' (no modifier) | | `rangeSelectionColumnSpanning` | boolean | True | Allow range selections to span multiple columns | | `trapFocus` | boolean | False | Prevent keyboard focus from leaving the grid | #### Selection Blending Props | Property | Type | Default | Description | |----------|------|---------|-------------| | `rowSelectionBlending` | string | 'exclusive' | 'exclusive' clears others, 'mixed' allows combining | | `columnSelectionBlending` | string | 'exclusive' | 'exclusive' clears others, 'mixed' allows combining | | `rangeSelectionBlending` | string | 'exclusive' | 'exclusive' clears others, 'mixed' allows combining | #### Selection Constraint Props | Property | Type | Default | Description | |----------|------|---------|-------------| | `unselectableRows` | list | - | Row indices that cannot be selected | | `unselectableColumns` | list | - | Column indices that cannot be selected | | `selectionColumnMin` | number | 0 | Minimum column index that can be selected | #### Selection Output Props | Property | Type | Description | |----------|------|-------------| | `selectedCell` | dict | Currently selected cell: `{col, row}` | | `selectedRows` | list | Selected row indices | | `selectedColumns` | list | Selected column indices | | `selectedRange` | dict | Primary selected range: `{startCol, startRow, endCol, endRow}` | | `selectedRanges` | list | Additional ranges when using multi-rect mode | #### Visual Props | Property | Type | Default | Description | |----------|------|---------|-------------| | `drawFocusRing` | boolean | True | Show focus ring around selected cell | | `spanRangeBehavior` | string | 'default' | 'default' expands to full spans, 'allowPartial' allows partial | --- *Source: /reference/selection* *Generated with dash-improve-my-llms*