# Cell Types > Detailed documentation for all basic and advanced cell types. --- .. llms_copy::references/cell-types .. toc:: ### Overview **Basic Cell Types** (from core glide-data-grid): text, number, boolean, markdown, uri, image, bubble, drilldown, rowid, protected, loading **Advanced Cell Types** (custom renderers): dropdown, multi-select, button, tags, star, date-picker, range, links, tree-view, user-profile, spinner, sparkline ### Basic Cell Types #### Text Standard text display and editing. Auto-detected from Python strings. .. exec::examples.reference.cell_types.text :code: false ```python # File: examples/reference/cell_types/text.py import dash_glide_grid as dgg columns = [ {"title": "Name", "id": "name", "width": 140}, {"title": "Title", "id": "title", "width": 160}, {"title": "Department", "id": "department", "width": 120}, {"title": "Location", "id": "location", "width": 120}, ] data = [ {"name": "Alice Johnson", "title": "Software Engineer", "department": "Engineering", "location": "New York"}, {"name": "Bob Smith", "title": "Product Manager", "department": "Product", "location": "San Francisco"}, {"name": "Carol White", "title": "Data Scientist", "department": "Analytics", "location": "Austin"}, {"name": "David Brown", "title": "DevOps Engineer", "department": "Engineering", "location": "Seattle"}, {"name": "Eve Martinez", "title": "UX Designer", "department": "Design", "location": "Los Angeles"}, {"name": "Frank Lee", "title": "Backend Developer", "department": "Engineering", "location": "Boston"}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-text"}, columns=columns, data=data, height=260, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Number Numeric values with formatting support. Auto-detected from Python numbers. .. exec::examples.reference.cell_types.number :code: false ```python # File: examples/reference/cell_types/number.py import dash_glide_grid as dgg columns = [ {"title": "Product", "id": "product", "width": 140}, {"title": "Price", "id": "price", "width": 100}, {"title": "Quantity", "id": "quantity", "width": 100}, {"title": "Rating", "id": "rating", "width": 100}, {"title": "Change %", "id": "change", "width": 100}, ] data = [ {"product": "Widget A", "price": 29.99, "quantity": 150, "rating": 4.5, "change": 12.5}, {"product": "Widget B", "price": 49.99, "quantity": 85, "rating": 4.8, "change": -3.2}, {"product": "Gadget X", "price": 199.00, "quantity": 42, "rating": 4.2, "change": 8.7}, {"product": "Gadget Y", "price": 149.50, "quantity": 200, "rating": 3.9, "change": -15.4}, {"product": "Tool Pro", "price": 89.99, "quantity": 0, "rating": 4.6, "change": 0.0}, {"product": "Tool Basic", "price": 39.99, "quantity": 500, "rating": 4.0, "change": 25.0}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-number"}, columns=columns, data=data, height=260, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Boolean Checkbox display for true/false values. Auto-detected from Python booleans. .. exec::examples.reference.cell_types.boolean :code: false ```python # File: examples/reference/cell_types/boolean.py import dash_glide_grid as dgg columns = [ {"title": "Feature", "id": "feature", "width": 180}, {"title": "Enabled", "id": "enabled", "width": 100}, {"title": "Required", "id": "required", "width": 100}, {"title": "Beta", "id": "beta", "width": 100}, ] data = [ {"feature": "Two-Factor Authentication", "enabled": True, "required": True, "beta": False}, {"feature": "Dark Mode", "enabled": True, "required": False, "beta": False}, {"feature": "Email Notifications", "enabled": False, "required": False, "beta": False}, {"feature": "API Access", "enabled": True, "required": False, "beta": True}, {"feature": "Advanced Analytics", "enabled": False, "required": False, "beta": True}, {"feature": "Auto-Save", "enabled": True, "required": True, "beta": False}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-boolean"}, columns=columns, data=data, height=260, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Markdown Rich text with markdown formatting. Use `kind: "markdown"` with `data` containing markdown text. .. exec::examples.reference.cell_types.markdown :code: false ```python # File: examples/reference/cell_types/markdown.py import dash_glide_grid as dgg columns = [ {"title": "Title", "id": "title", "width": 160}, {"title": "Description", "id": "description", "width": 220}, {"title": "Status", "id": "status", "width": 120}, ] data = [ { "title": "Feature Request", "description": {"kind": "markdown", "data": "**Bold** feature with `code` snippet"}, "status": {"kind": "markdown", "data": "🟢 *Active*"}, }, { "title": "Bug Report", "description": {"kind": "markdown", "data": "*Italic* text with ~~strikethrough~~"}, "status": {"kind": "markdown", "data": "🔴 **Critical**"}, }, { "title": "Documentation", "description": {"kind": "markdown", "data": "[Link to docs](https://docs.example.com)"}, "status": {"kind": "markdown", "data": "🟡 *Pending*"}, }, { "title": "Enhancement", "description": {"kind": "markdown", "data": "List: `item1`, `item2`, `item3`"}, "status": {"kind": "markdown", "data": "🔵 *In Review*"}, }, { "title": "Refactor", "description": {"kind": "markdown", "data": "Mixed **bold** and *italic* text"}, "status": {"kind": "markdown", "data": "⚪ *Backlog*"}, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-markdown"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### URI Clickable links. Use `kind: "uri"` with `data` (URL) and optional `displayData` (label). .. exec::examples.reference.cell_types.uri :code: false ```python # File: examples/reference/cell_types/uri.py import dash_glide_grid as dgg columns = [ {"title": "Service", "id": "service", "width": 140}, {"title": "Website", "id": "website", "width": 140}, {"title": "Docs", "id": "docs", "width": 140}, ] data = [ { "service": "GitHub", "website": {"kind": "uri", "data": "https://github.com", "displayData": "github.com"}, "docs": {"kind": "uri", "data": "https://docs.github.com", "displayData": "Documentation"}, }, { "service": "Plotly", "website": {"kind": "uri", "data": "https://plotly.com", "displayData": "plotly.com"}, "docs": {"kind": "uri", "data": "https://dash.plotly.com", "displayData": "Dash Docs"}, }, { "service": "Python", "website": {"kind": "uri", "data": "https://python.org", "displayData": "python.org"}, "docs": {"kind": "uri", "data": "https://docs.python.org", "displayData": "Python Docs"}, }, { "service": "MDN", "website": {"kind": "uri", "data": "https://developer.mozilla.org", "displayData": "MDN Web Docs"}, "docs": {"kind": "uri", "data": "https://developer.mozilla.org/docs", "displayData": "Web APIs"}, }, { "service": "npm", "website": {"kind": "uri", "data": "https://npmjs.com", "displayData": "npmjs.com"}, "docs": {"kind": "uri", "data": "https://docs.npmjs.com", "displayData": "npm Docs"}, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-uri"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Image Display one or more images. Use `kind: "image"` with `data` as array of image URLs. .. exec::examples.reference.cell_types.image :code: false ```python # File: examples/reference/cell_types/image.py import dash_glide_grid as dgg columns = [ {"title": "Name", "id": "name", "width": 140}, {"title": "Avatar", "id": "avatar", "width": 80}, {"title": "Team", "id": "team", "width": 120}, ] data = [ { "name": "Alice Johnson", "avatar": {"kind": "image", "data": ["https://i.pravatar.cc/40?u=alice"]}, "team": {"kind": "image", "data": ["https://i.pravatar.cc/30?u=team1", "https://i.pravatar.cc/30?u=team2"]}, }, { "name": "Bob Smith", "avatar": {"kind": "image", "data": ["https://i.pravatar.cc/40?u=bob"]}, "team": {"kind": "image", "data": ["https://i.pravatar.cc/30?u=team3", "https://i.pravatar.cc/30?u=team4", "https://i.pravatar.cc/30?u=team5"]}, }, { "name": "Carol White", "avatar": {"kind": "image", "data": ["https://i.pravatar.cc/40?u=carol"]}, "team": {"kind": "image", "data": ["https://i.pravatar.cc/30?u=team6"]}, }, { "name": "David Brown", "avatar": {"kind": "image", "data": ["https://i.pravatar.cc/40?u=david"]}, "team": {"kind": "image", "data": ["https://i.pravatar.cc/30?u=team7", "https://i.pravatar.cc/30?u=team8"]}, }, { "name": "Eve Martinez", "avatar": {"kind": "image", "data": ["https://i.pravatar.cc/40?u=eve"]}, "team": {"kind": "image", "data": ["https://i.pravatar.cc/30?u=team9", "https://i.pravatar.cc/30?u=team10", "https://i.pravatar.cc/30?u=team11", "https://i.pravatar.cc/30?u=team12"]}, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-image"}, columns=columns, data=data, height=230, rowHeight=45, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Bubble Tag-like bubbles for lists. Use `kind: "bubble"` with `data` as array of strings. .. exec::examples.reference.cell_types.bubble :code: false ```python # File: examples/reference/cell_types/bubble.py import dash_glide_grid as dgg columns = [ {"title": "Project", "id": "project", "width": 140}, {"title": "Technologies", "id": "tech", "width": 200}, {"title": "Tags", "id": "tags", "width": 160}, ] data = [ { "project": "E-commerce App", "tech": {"kind": "bubble", "data": ["React", "Node.js", "PostgreSQL"]}, "tags": {"kind": "bubble", "data": ["web", "mobile"]}, }, { "project": "Data Pipeline", "tech": {"kind": "bubble", "data": ["Python", "Spark", "Kafka", "AWS"]}, "tags": {"kind": "bubble", "data": ["backend", "data"]}, }, { "project": "Mobile App", "tech": {"kind": "bubble", "data": ["Flutter", "Firebase"]}, "tags": {"kind": "bubble", "data": ["mobile", "ios", "android"]}, }, { "project": "ML Service", "tech": {"kind": "bubble", "data": ["Python", "TensorFlow", "Docker", "K8s"]}, "tags": {"kind": "bubble", "data": ["ai", "ml", "backend"]}, }, { "project": "Dashboard", "tech": {"kind": "bubble", "data": ["Dash", "Plotly"]}, "tags": {"kind": "bubble", "data": ["visualization"]}, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-bubble"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Drilldown Breadcrumb-style navigation path. Use `kind: "drilldown"` with `data` as array of `{text, img?}` objects. .. exec::examples.reference.cell_types.drilldown :code: false ```python # File: examples/reference/cell_types/drilldown.py import dash_glide_grid as dgg columns = [ {"title": "Employee", "id": "employee", "width": 140}, {"title": "Department Path", "id": "path", "width": 260}, ] data = [ { "employee": "Alice Johnson", "path": { "kind": "drilldown", "data": [ {"text": "Engineering", "img": "https://i.pravatar.cc/20?u=eng"}, {"text": "Backend", "img": "https://i.pravatar.cc/20?u=back"}, {"text": "APIs"}, ], }, }, { "employee": "Bob Smith", "path": { "kind": "drilldown", "data": [ {"text": "Product", "img": "https://i.pravatar.cc/20?u=prod"}, {"text": "Mobile"}, ], }, }, { "employee": "Carol White", "path": { "kind": "drilldown", "data": [ {"text": "Data Science", "img": "https://i.pravatar.cc/20?u=data"}, {"text": "ML", "img": "https://i.pravatar.cc/20?u=ml"}, {"text": "NLP"}, ], }, }, { "employee": "David Brown", "path": { "kind": "drilldown", "data": [ {"text": "Infrastructure"}, {"text": "DevOps"}, ], }, }, { "employee": "Eve Martinez", "path": { "kind": "drilldown", "data": [ {"text": "Design", "img": "https://i.pravatar.cc/20?u=design"}, ], }, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-drilldown"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Row ID Display row identifiers with monospace styling. Use `kind: "rowid"` with `data` as the ID string. .. exec::examples.reference.cell_types.rowid :code: false ```python # File: examples/reference/cell_types/rowid.py import dash_glide_grid as dgg columns = [ {"title": "ID", "id": "id", "width": 100}, {"title": "Name", "id": "name", "width": 140}, {"title": "Type", "id": "type", "width": 120}, ] data = [ {"id": {"kind": "rowid", "data": "ORD-001"}, "name": "Order A", "type": "Standard"}, {"id": {"kind": "rowid", "data": "ORD-002"}, "name": "Order B", "type": "Express"}, {"id": {"kind": "rowid", "data": "ORD-003"}, "name": "Order C", "type": "Standard"}, {"id": {"kind": "rowid", "data": "INV-001"}, "name": "Invoice X", "type": "Monthly"}, {"id": {"kind": "rowid", "data": "INV-002"}, "name": "Invoice Y", "type": "Quarterly"}, {"id": {"kind": "rowid", "data": "REF-001"}, "name": "Refund Z", "type": "Partial"}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-rowid"}, columns=columns, data=data, height=260, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Protected Masked/hidden content indicator. Use `kind: "protected"` for sensitive data. .. exec::examples.reference.cell_types.protected :code: false ```python # File: examples/reference/cell_types/protected.py import dash_glide_grid as dgg columns = [ {"title": "Field", "id": "field", "width": 140}, {"title": "Value", "id": "value", "width": 140}, {"title": "Protected", "id": "protected", "width": 100}, ] data = [ {"field": "Password", "value": "********", "protected": {"kind": "protected"}}, {"field": "API Key", "value": "sk-...abc", "protected": {"kind": "protected"}}, {"field": "Secret Token", "value": "Hidden", "protected": {"kind": "protected"}}, {"field": "Username", "value": "admin", "protected": {"kind": "protected"}}, {"field": "SSN", "value": "***-**-1234", "protected": {"kind": "protected"}}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-protected"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Loading Skeleton loading placeholder. Use `kind: "loading"` with optional `skeletonWidth` and `skeletonHeight`. .. exec::examples.reference.cell_types.loading :code: false ```python # File: examples/reference/cell_types/loading.py import dash_glide_grid as dgg columns = [ {"title": "Item", "id": "item", "width": 140}, {"title": "Status", "id": "status", "width": 120}, {"title": "Progress", "id": "progress", "width": 120}, ] data = [ {"item": "Task 1", "status": {"kind": "loading", "skeletonWidth": 80, "skeletonHeight": 16}, "progress": {"kind": "loading", "skeletonWidth": 60}}, {"item": "Task 2", "status": {"kind": "loading", "skeletonWidth": 80, "skeletonHeight": 16}, "progress": {"kind": "loading", "skeletonWidth": 60}}, {"item": "Task 3", "status": {"kind": "loading", "skeletonWidth": 80, "skeletonHeight": 16}, "progress": {"kind": "loading", "skeletonWidth": 60}}, {"item": "Task 4", "status": {"kind": "loading", "skeletonWidth": 80, "skeletonHeight": 16}, "progress": {"kind": "loading", "skeletonWidth": 60}}, {"item": "Task 5", "status": {"kind": "loading", "skeletonWidth": 80, "skeletonHeight": 16}, "progress": {"kind": "loading", "skeletonWidth": 60}}, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-loading"}, columns=columns, data=data, height=230, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true ### Advanced Cell Types Advanced cell types are custom renderers added to the Dash wrapper. #### Dropdown Single-select dropdown. Use `kind: "dropdown-cell"` with `data.value`, `data.options`, and `data.allowedValues`. .. exec::examples.reference.cell_types.dropdown :code: false ```python # File: examples/reference/cell_types/dropdown.py import dash_glide_grid as dgg from dash import callback, Input, Output, State import copy # Status color pairs (light/dark theme) STATUS_COLORS = { "active": {"light": "#a8e6cf", "dark": "#2e7d32"}, "pending": {"light": "#fff3cd", "dark": "#f57f17"}, "inactive": {"light": "#ffcdd2", "dark": "#c62828"}, "review": {"light": "#e1bee7", "dark": "#7b1fa2"}, "approved": {"light": "#b3e5fc", "dark": "#1565c0"}, "archived": {"light": "#e0e0e0", "dark": "#616161"}, } STATUS_LABELS = { "active": "Active", "pending": "Pending", "inactive": "Inactive", "review": "In Review", "approved": "Approved", "archived": "Archived", } PRIORITY_COLORS = { "high": {"light": "#ffcdd2", "dark": "#c62828"}, "medium": {"light": "#fff3cd", "dark": "#f57f17"}, "low": {"light": "#a8e6cf", "dark": "#2e7d32"}, } PRIORITY_LABELS = { "high": "High", "medium": "Medium", "low": "Low", } def get_status_options(theme="light"): return [ {"value": k, "label": v, "color": STATUS_COLORS[k][theme]} for k, v in STATUS_LABELS.items() ] def get_priority_options(theme="light"): return [ {"value": k, "label": v, "color": PRIORITY_COLORS[k][theme]} for k, v in PRIORITY_LABELS.items() ] status_options = get_status_options("light") priority_options = get_priority_options("light") columns = [ {"title": "Task", "id": "task", "width": 180}, {"title": "Status", "id": "status", "width": 130}, {"title": "Priority", "id": "priority", "width": 130}, ] data = [ { "task": "Review pull request", "status": { "kind": "dropdown-cell", "data": {"value": "active", "options": status_options, "allowedValues": [o["value"] for o in status_options]}, "allowOverlay": True, }, "priority": { "kind": "dropdown-cell", "data": {"value": "high", "options": priority_options, "allowedValues": [o["value"] for o in priority_options]}, "allowOverlay": True, }, }, { "task": "Update documentation", "status": { "kind": "dropdown-cell", "data": {"value": "pending", "options": status_options, "allowedValues": [o["value"] for o in status_options]}, "allowOverlay": True, }, "priority": { "kind": "dropdown-cell", "data": {"value": "medium", "options": priority_options, "allowedValues": [o["value"] for o in priority_options]}, "allowOverlay": True, }, }, { "task": "Fix critical bug", "status": { "kind": "dropdown-cell", "data": {"value": "review", "options": status_options, "allowedValues": [o["value"] for o in status_options]}, "allowOverlay": True, }, "priority": { "kind": "dropdown-cell", "data": {"value": "high", "options": priority_options, "allowedValues": [o["value"] for o in priority_options]}, "allowOverlay": True, }, }, { "task": "Refactor module", "status": { "kind": "dropdown-cell", "data": {"value": "approved", "options": status_options, "allowedValues": [o["value"] for o in status_options]}, "allowOverlay": True, }, "priority": { "kind": "dropdown-cell", "data": {"value": "low", "options": priority_options, "allowedValues": [o["value"] for o in priority_options]}, "allowOverlay": True, }, }, { "task": "Archive old project", "status": { "kind": "dropdown-cell", "data": {"value": "archived", "options": status_options, "allowedValues": [o["value"] for o in status_options]}, "allowOverlay": True, }, "priority": { "kind": "dropdown-cell", "data": {"value": "low", "options": priority_options, "allowedValues": [o["value"] for o in priority_options]}, "allowOverlay": True, }, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-dropdown"}, columns=columns, data=data, height=230, sortable=True, ) @callback( Output({"type": "glide-grid", "index": "cells-dropdown"}, "data"), Input("color-scheme-storage", "data"), State({"type": "glide-grid", "index": "cells-dropdown"}, "data"), ) def update_dropdown_colors(color_scheme, current_data): """Update dropdown colors when theme changes.""" if not current_data: return current_data theme = color_scheme if color_scheme in ("light", "dark") else "light" new_status_options = get_status_options(theme) new_priority_options = get_priority_options(theme) updated_data = copy.deepcopy(current_data) for row in updated_data: if isinstance(row.get("status"), dict) and row["status"].get("kind") == "dropdown-cell": row["status"]["data"]["options"] = new_status_options if isinstance(row.get("priority"), dict) and row["priority"].get("kind") == "dropdown-cell": row["priority"]["data"]["options"] = new_priority_options return updated_data ``` :defaultExpanded: false :withExpandedButton: true #### Multi-Select Multiple selection with tags. Use `kind: "multi-select-cell"` with `data.values`, `data.options`, `data.allowedValues`. .. exec::examples.reference.cell_types.multiselect :code: false ```python # File: examples/reference/cell_types/multiselect.py import dash_glide_grid as dgg from dash import callback, Input, Output, State import copy # Skill color pairs (light/dark theme) SKILL_COLORS = { "python": {"light": "#bbdefb", "dark": "#1565c0"}, "javascript": {"light": "#fff9c4", "dark": "#f9a825"}, "react": {"light": "#b2ebf2", "dark": "#00838f"}, "sql": {"light": "#c5cae9", "dark": "#303f9f"}, "rust": {"light": "#ffccbc", "dark": "#d84315"}, "go": {"light": "#b2dfdb", "dark": "#00695c"}, "typescript": {"light": "#d1c4e9", "dark": "#512da8"}, "docker": {"light": "#b3e5fc", "dark": "#0277bd"}, } SKILL_LABELS = { "python": "Python", "javascript": "JavaScript", "react": "React", "sql": "SQL", "rust": "Rust", "go": "Go", "typescript": "TypeScript", "docker": "Docker", } def get_skill_options(theme="light"): return [ {"value": k, "label": v, "color": SKILL_COLORS[k][theme]} for k, v in SKILL_LABELS.items() ] skill_options = get_skill_options("light") columns = [ {"title": "Developer", "id": "developer", "width": 140}, {"title": "Skills", "id": "skills", "width": 280}, ] data = [ { "developer": "Alice", "skills": { "kind": "multi-select-cell", "data": { "values": ["python", "rust", "docker"], "options": skill_options, "allowedValues": [o["value"] for o in skill_options], "allowDuplicates": False, "allowCreation": True, }, "allowOverlay": True, }, }, { "developer": "Bob", "skills": { "kind": "multi-select-cell", "data": { "values": ["javascript", "react", "typescript"], "options": skill_options, "allowedValues": [o["value"] for o in skill_options], "allowDuplicates": False, "allowCreation": True, }, "allowOverlay": True, }, }, { "developer": "Carol", "skills": { "kind": "multi-select-cell", "data": { "values": ["python", "sql"], "options": skill_options, "allowedValues": [o["value"] for o in skill_options], "allowDuplicates": False, "allowCreation": True, }, "allowOverlay": True, }, }, { "developer": "David", "skills": { "kind": "multi-select-cell", "data": { "values": ["go", "docker", "rust"], "options": skill_options, "allowedValues": [o["value"] for o in skill_options], "allowDuplicates": False, "allowCreation": True, }, "allowOverlay": True, }, }, { "developer": "Eve", "skills": { "kind": "multi-select-cell", "data": { "values": ["python", "javascript", "go", "sql"], "options": skill_options, "allowedValues": [o["value"] for o in skill_options], "allowDuplicates": False, "allowCreation": True, }, "allowOverlay": True, }, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-multiselect"}, columns=columns, data=data, height=230, sortable=True, ) @callback( Output({"type": "glide-grid", "index": "cells-multiselect"}, "data"), Input("color-scheme-storage", "data"), State({"type": "glide-grid", "index": "cells-multiselect"}, "data"), ) def update_multiselect_colors(color_scheme, current_data): """Update multi-select colors when theme changes.""" if not current_data: return current_data theme = color_scheme if color_scheme in ("light", "dark") else "light" new_skill_options = get_skill_options(theme) updated_data = copy.deepcopy(current_data) for row in updated_data: if isinstance(row.get("skills"), dict) and row["skills"].get("kind") == "multi-select-cell": row["skills"]["data"]["options"] = new_skill_options return updated_data ``` :defaultExpanded: false :withExpandedButton: true #### Button Cell Clickable buttons. Use `kind: "button-cell"` with `title`, `backgroundColor`, `color`, `borderRadius`. Handle clicks via `buttonClicked` callback. .. exec::examples.reference.cell_types.button :code: false ```python # File: examples/reference/cell_types/button.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output, State, no_update, dcc, ctx import copy # Button color pairs (light/dark theme) BUTTON_COLORS = { "view": { "light": {"bg": "#228be6", "text": "#ffffff"}, "dark": {"bg": "#1971c2", "text": "#ffffff"}, }, "delete": { "light": {"bg": "#fa5252", "text": "#ffffff"}, "dark": {"bg": "#e03131", "text": "#ffffff"}, }, } def get_button_style(button_type, theme="light"): colors = BUTTON_COLORS[button_type][theme] return {"backgroundColor": colors["bg"], "color": colors["text"]} columns = [ {"title": "Name", "id": "name", "width": 150}, {"title": "Email", "id": "email", "width": 200}, {"title": "Action", "id": "action", "width": 80}, {"title": "Delete", "id": "delete", "width": 80}, ] view_style = get_button_style("view", "light") delete_style = get_button_style("delete", "light") initial_data = [ { "name": "Alice Johnson", "email": "alice@example.com", "action": { "kind": "button-cell", "title": "View", "backgroundColor": view_style["backgroundColor"], "color": view_style["color"], "borderRadius": 4, }, "delete": { "kind": "button-cell", "title": "Delete", "backgroundColor": delete_style["backgroundColor"], "color": delete_style["color"], "borderRadius": 4, }, }, { "name": "Bob Smith", "email": "bob@example.com", "action": { "kind": "button-cell", "title": "View", "backgroundColor": view_style["backgroundColor"], "color": view_style["color"], "borderRadius": 4, }, "delete": { "kind": "button-cell", "title": "Delete", "backgroundColor": delete_style["backgroundColor"], "color": delete_style["color"], "borderRadius": 4, }, }, { "name": "Carol White", "email": "carol@example.com", "action": { "kind": "button-cell", "title": "View", "backgroundColor": view_style["backgroundColor"], "color": view_style["color"], "borderRadius": 4, }, "delete": { "kind": "button-cell", "title": "Delete", "backgroundColor": delete_style["backgroundColor"], "color": delete_style["color"], "borderRadius": 4, }, }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-button"}, columns=columns, data=initial_data, height=200, sortable=True, ), # Store for tracking pending delete row dcc.Store(id="button-pending-delete-row", data=None), # Store for view modal data dcc.Store(id="button-view-modal-data", data=None), # View Details Modal dmc.Modal( id="button-view-modal", title="User Details", centered=True, children=[ dmc.Stack( id="button-view-modal-content", gap="xs", children=[], ), dmc.Group( justify="flex-end", mt="md", children=[ dmc.Button("Close", id="button-view-modal-close", variant="light"), ], ), ], ), # Delete Confirmation Modal dmc.Modal( id="button-delete-modal", title="Confirm Delete", centered=True, children=[ dmc.Text(id="button-delete-modal-text", mb="md"), dmc.Group( justify="flex-end", children=[ dmc.Button( "Cancel", id="button-delete-modal-cancel", variant="light", ), dmc.Button( "Delete", id="button-delete-modal-confirm", color="red", ), ], ), ], ), dmc.Text( id="button-click-output", size="sm", c="dimmed", children="Click 'View' to see details or 'Delete' to remove a row", ), ] ) @callback( Output("button-view-modal", "opened"), Output("button-view-modal-content", "children"), Output("button-delete-modal", "opened"), Output("button-delete-modal-text", "children"), Output("button-pending-delete-row", "data"), Output("button-click-output", "children"), Input({"type": "glide-grid", "index": "cells-button"}, "buttonClicked"), Input("button-view-modal-close", "n_clicks"), Input("button-delete-modal-cancel", "n_clicks"), State({"type": "glide-grid", "index": "cells-button"}, "data"), prevent_initial_call=True, ) def handle_button_click(click_info, view_close, delete_cancel, grid_data): """Handle button clicks and modal open/close.""" triggered = ctx.triggered_id # Close view modal if triggered == "button-view-modal-close": return False, no_update, no_update, no_update, no_update, no_update # Cancel delete if triggered == "button-delete-modal-cancel": return no_update, no_update, False, no_update, None, "Delete cancelled" # Handle button clicks from grid if click_info: row_data = grid_data[click_info["row"]] name = row_data["name"] email = row_data["email"] if click_info["title"] == "View": # Open view modal with user details content = [ dmc.Text([dmc.Text("Name: ", fw=600, span=True), name]), dmc.Text([dmc.Text("Email: ", fw=600, span=True), email]), dmc.Text([dmc.Text("Row: ", fw=600, span=True), str(click_info["row"])]), ] return ( True, content, False, no_update, no_update, f"Viewing details for {name}", ) elif click_info["title"] == "Delete": # Open delete confirmation modal return ( False, no_update, True, f"Are you sure you want to delete {name}? This action cannot be undone.", click_info["row"], f"Confirm delete for {name}", ) return no_update, no_update, no_update, no_update, no_update, no_update @callback( Output({"type": "glide-grid", "index": "cells-button"}, "data"), Output("button-delete-modal", "opened", allow_duplicate=True), Output("button-click-output", "children", allow_duplicate=True), Input("button-delete-modal-confirm", "n_clicks"), State("button-pending-delete-row", "data"), State({"type": "glide-grid", "index": "cells-button"}, "data"), prevent_initial_call=True, ) def confirm_delete(n_clicks, pending_row, grid_data): """Delete the row when confirmed.""" if pending_row is not None and grid_data: deleted_name = grid_data[pending_row]["name"] new_data = [row for i, row in enumerate(grid_data) if i != pending_row] return new_data, False, f"Deleted {deleted_name}" return no_update, False, no_update @callback( Output({"type": "glide-grid", "index": "cells-button"}, "data", allow_duplicate=True), Input("color-scheme-storage", "data"), State({"type": "glide-grid", "index": "cells-button"}, "data"), prevent_initial_call=True, ) def update_button_colors(color_scheme, current_data): """Update button colors when theme changes.""" if not current_data: return current_data theme = color_scheme if color_scheme in ("light", "dark") else "light" new_view_style = get_button_style("view", theme) new_delete_style = get_button_style("delete", theme) updated_data = copy.deepcopy(current_data) for row in updated_data: if isinstance(row.get("action"), dict) and row["action"].get("kind") == "button-cell": row["action"]["backgroundColor"] = new_view_style["backgroundColor"] row["action"]["color"] = new_view_style["color"] if isinstance(row.get("delete"), dict) and row["delete"].get("kind") == "button-cell": row["delete"]["backgroundColor"] = new_delete_style["backgroundColor"] row["delete"]["color"] = new_delete_style["color"] return updated_data ``` :defaultExpanded: false :withExpandedButton: true #### Tags Cell Editable tag chips. Use `kind: "tags-cell"` with `tags` (array) and `possibleTags` (array of `{tag, color}`). .. exec::examples.reference.cell_types.tags :code: false ```python # File: examples/reference/cell_types/tags.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output, State import copy # Tag color pairs (light/dark theme) TAG_COLORS = { "Bug": {"light": "#ffcdd2", "dark": "#c62828"}, "Feature": {"light": "#e1bee7", "dark": "#7b1fa2"}, "Enhancement": {"light": "#bbdefb", "dark": "#1565c0"}, "Docs": {"light": "#fff9c4", "dark": "#f9a825"}, "Urgent": {"light": "#f8bbd9", "dark": "#ad1457"}, } def get_possible_tags(theme="light"): return [ {"tag": tag, "color": colors[theme]} for tag, colors in TAG_COLORS.items() ] possible_tags = get_possible_tags("light") columns = [ {"title": "Issue", "id": "issue", "width": 200}, {"title": "Tags", "id": "tags", "width": 220}, ] data = [ { "issue": "Fix login redirect", "tags": { "kind": "tags-cell", "tags": ["Bug", "Urgent"], "possibleTags": possible_tags, }, }, { "issue": "Add dark mode", "tags": { "kind": "tags-cell", "tags": ["Feature", "Enhancement"], "possibleTags": possible_tags, }, }, { "issue": "Update API docs", "tags": { "kind": "tags-cell", "tags": ["Docs"], "possibleTags": possible_tags, }, }, { "issue": "Improve performance", "tags": { "kind": "tags-cell", "tags": ["Enhancement"], "possibleTags": possible_tags, }, }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-tags"}, columns=columns, data=data, height=240, sortable=True, ), dmc.Text( id="tags-output", size="sm", c="dimmed", children="Click a tags cell to edit", ), ] ) @callback( Output("tags-output", "children"), Input({"type": "glide-grid", "index": "cells-tags"}, "cellEdited"), prevent_initial_call=True, ) def show_tags_edit(edit): if edit and edit.get("col") == 1: tags = edit["value"].get("tags", []) return f"Tags updated: {', '.join(tags)}" return "Click a tags cell to edit" @callback( Output({"type": "glide-grid", "index": "cells-tags"}, "data"), Input("color-scheme-storage", "data"), State({"type": "glide-grid", "index": "cells-tags"}, "data"), ) def update_tags_colors(color_scheme, current_data): """Update tag colors when theme changes.""" if not current_data: return current_data theme = color_scheme if color_scheme in ("light", "dark") else "light" new_possible_tags = get_possible_tags(theme) updated_data = copy.deepcopy(current_data) for row in updated_data: if isinstance(row.get("tags"), dict) and row["tags"].get("kind") == "tags-cell": row["tags"]["possibleTags"] = new_possible_tags return updated_data ``` :defaultExpanded: false :withExpandedButton: true #### Star Cell Star rating display/editor. Use `kind: "star-cell"` with `rating` and `maxStars`. .. exec::examples.reference.cell_types.star :code: false ```python # File: examples/reference/cell_types/star.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Product", "id": "product", "width": 180}, {"title": "Rating", "id": "rating", "width": 120}, {"title": "Reviews", "id": "reviews", "width": 80}, ] data = [ { "product": "Wireless Headphones", "rating": {"kind": "star-cell", "rating": 5, "maxStars": 5}, "reviews": 1234, }, { "product": "USB-C Hub", "rating": {"kind": "star-cell", "rating": 4, "maxStars": 5}, "reviews": 567, }, { "product": "Mechanical Keyboard", "rating": {"kind": "star-cell", "rating": 5, "maxStars": 5}, "reviews": 892, }, { "product": "Monitor Stand", "rating": {"kind": "star-cell", "rating": 3, "maxStars": 5}, "reviews": 234, }, { "product": "Webcam", "rating": {"kind": "star-cell", "rating": 2, "maxStars": 5}, "reviews": 156, }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-star"}, columns=columns, data=data, height=260, sortable=True, ), dmc.Text( id="star-output", size="sm", c="dimmed", children="Click a star cell to change rating", ), ] ) @callback( Output("star-output", "children"), Input({"type": "glide-grid", "index": "cells-star"}, "cellEdited"), prevent_initial_call=True, ) def show_star_edit(edit): if edit and edit.get("col") == 1: rating = edit["value"].get("rating", 0) return f"Rating updated: {rating}/5 stars" return "Click a star cell to change rating" ``` :defaultExpanded: false :withExpandedButton: true #### Date Picker Date selection with calendar picker. Use `kind: "date-picker-cell"` with `date`, `displayDate`, `format`. .. exec::examples.reference.cell_types.date_picker :code: false ```python # File: examples/reference/cell_types/date_picker.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Task", "id": "task", "width": 180}, {"title": "Due Date", "id": "due_date", "width": 140}, {"title": "Status", "id": "status", "width": 100}, ] data = [ { "task": "Project kickoff", "due_date": { "kind": "date-picker-cell", "date": "2024-01-15", "displayDate": "Jan 15, 2024", "format": "date", }, "status": "Completed", }, { "task": "Design review", "due_date": { "kind": "date-picker-cell", "date": "2024-02-01", "displayDate": "Feb 1, 2024", "format": "date", }, "status": "Completed", }, { "task": "Development sprint", "due_date": { "kind": "date-picker-cell", "date": "2024-03-15", "displayDate": "Mar 15, 2024", "format": "date", }, "status": "In Progress", }, { "task": "Testing phase", "due_date": { "kind": "date-picker-cell", "date": "2024-04-01", "displayDate": "Apr 1, 2024", "format": "date", }, "status": "Pending", }, { "task": "Launch", "due_date": { "kind": "date-picker-cell", "date": None, "displayDate": "", "format": "date", }, "status": "Not Scheduled", }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-date-picker"}, columns=columns, data=data, height=260, sortable=True, ), dmc.Text( id="date-output", size="sm", c="dimmed", children="Click a date cell to open picker", ), ] ) @callback( Output("date-output", "children"), Input({"type": "glide-grid", "index": "cells-date-picker"}, "cellEdited"), prevent_initial_call=True, ) def show_date_edit(edit): if edit and edit.get("col") == 1: date = edit["value"].get("displayDate") or edit["value"].get("date") or "None" return f"Date updated: {date}" return "Click a date cell to open picker" ``` :defaultExpanded: false :withExpandedButton: true #### Range Progress bar with optional editing. Use `kind: "range-cell"` with `value`, `min`, `max`, `step`, `label`. .. exec::examples.reference.cell_types.range :code: false ```python # File: examples/reference/cell_types/range.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Task", "id": "task", "width": 160}, {"title": "Progress", "id": "progress", "width": 140}, {"title": "Assignee", "id": "assignee", "width": 100}, ] data = [ { "task": "Database migration", "progress": { "kind": "range-cell", "value": 100, "min": 0, "max": 100, "step": 5, "label": "100%", "readonly": True, }, "assignee": "Alice", }, { "task": "API integration", "progress": { "kind": "range-cell", "value": 75, "min": 0, "max": 100, "step": 5, "label": "75%", }, "assignee": "Bob", }, { "task": "UI redesign", "progress": { "kind": "range-cell", "value": 50, "min": 0, "max": 100, "step": 5, "label": "50%", }, "assignee": "Carol", }, { "task": "Testing suite", "progress": { "kind": "range-cell", "value": 25, "min": 0, "max": 100, "step": 5, "label": "25%", }, "assignee": "David", }, { "task": "Documentation", "progress": { "kind": "range-cell", "value": 10, "min": 0, "max": 100, "step": 5, "label": "10%", }, "assignee": "Eve", }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-range"}, columns=columns, data=data, height=260, sortable=True, ), dmc.Text( id="range-output", size="sm", c="dimmed", children="Click a progress cell to adjust (row 1 is readonly)", ), ] ) @callback( Output("range-output", "children"), Input({"type": "glide-grid", "index": "cells-range"}, "cellEdited"), prevent_initial_call=True, ) def show_range_edit(edit): if edit and edit.get("col") == 1: value = edit["value"].get("value", 0) return f"Progress updated: {value}%" return "Click a progress cell to adjust" ``` :defaultExpanded: false :withExpandedButton: true #### Links Multiple clickable links. Use `kind: "links-cell"` with `links` (array of `{title, href}`). Handle via `linkClicked` callback. .. exec::examples.reference.cell_types.links :code: false ```python # File: examples/reference/cell_types/links.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output columns = [ {"title": "Project", "id": "project", "width": 120}, {"title": "Links", "id": "links", "width": 200}, {"title": "Description", "id": "description", "width": 250}, ] data = [ { "project": "React", "links": { "kind": "links-cell", "links": [ {"title": "GitHub", "href": "https://github.com/facebook/react"}, {"title": "Docs", "href": "https://react.dev"}, {"title": "NPM", "href": "https://www.npmjs.com/package/react"}, ], }, "description": "JavaScript library for building UIs", }, { "project": "Dash", "links": { "kind": "links-cell", "links": [ {"title": "GitHub", "href": "https://github.com/plotly/dash"}, {"title": "Docs", "href": "https://dash.plotly.com"}, ], }, "description": "Python framework for analytical apps", }, { "project": "Mantine", "links": { "kind": "links-cell", "links": [ {"title": "GitHub", "href": "https://github.com/mantinedev/mantine"}, {"title": "Docs", "href": "https://mantine.dev"}, ], }, "description": "React components library", }, ] component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-links"}, columns=columns, data=data, height=200, sortable=True, ), dmc.Text( id="links-output", size="sm", c="dimmed", children="Click a link to open in new tab", ), ] ) @callback( Output("links-output", "children"), Input({"type": "glide-grid", "index": "cells-links"}, "linkClicked"), prevent_initial_call=True, ) def show_link_click(link_info): if link_info: return f"Clicked: {link_info.get('title', '')} ({link_info.get('href', '')})" return "Click a link to open in new tab" ``` :defaultExpanded: false :withExpandedButton: true #### Tree View Hierarchical tree nodes. Use `kind: "tree-view-cell"` with `text`, `depth`, `isOpen`, `canOpen`. Handle via `treeNodeToggled` callback. .. exec::examples.reference.cell_types.tree_view :code: false ```python # File: examples/reference/cell_types/tree_view.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output, State, dcc # Hierarchical data structure TREE_DATA = [ {"id": "root", "parent_id": None, "name": "Project Root", "type": "folder"}, {"id": "src", "parent_id": "root", "name": "src", "type": "folder"}, {"id": "src_app", "parent_id": "src", "name": "App.tsx", "type": "file"}, {"id": "src_index", "parent_id": "src", "name": "index.tsx", "type": "file"}, {"id": "src_components", "parent_id": "src", "name": "components", "type": "folder"}, {"id": "src_components_btn", "parent_id": "src_components", "name": "Button.tsx", "type": "file"}, {"id": "public", "parent_id": "root", "name": "public", "type": "folder"}, {"id": "public_index", "parent_id": "public", "name": "index.html", "type": "file"}, {"id": "package", "parent_id": "root", "name": "package.json", "type": "file"}, ] columns = [ {"title": "Name", "id": "name", "width": 220}, {"title": "Type", "id": "type", "width": 80}, ] def get_depth(node_id, tree_data): depth = 0 node = next((n for n in tree_data if n["id"] == node_id), None) while node and node["parent_id"]: depth += 1 node = next((n for n in tree_data if n["id"] == node["parent_id"]), None) return depth def has_children(node_id, tree_data): return any(n["parent_id"] == node_id for n in tree_data) def build_visible_rows(tree_data, expanded): visible = [] def add_children(parent_id): children = sorted( [n for n in tree_data if n["parent_id"] == parent_id], key=lambda x: (0 if x["type"] == "folder" else 1, x["name"]), ) for node in children: depth = get_depth(node["id"], tree_data) can_open = has_children(node["id"], tree_data) is_open = node["id"] in expanded visible.append({ "id": node["id"], "name": { "kind": "tree-view-cell", "text": node["name"], "depth": depth, "isOpen": is_open, "canOpen": can_open, }, "type": node["type"].capitalize(), }) if is_open and can_open: add_children(node["id"]) # Add root root = next((n for n in tree_data if n["id"] == "root"), None) if root: visible.append({ "id": "root", "name": { "kind": "tree-view-cell", "text": root["name"], "depth": 0, "isOpen": "root" in expanded, "canOpen": has_children("root", tree_data), }, "type": "Folder", }) if "root" in expanded: add_children("root") return visible INITIAL_EXPANDED = {"root", "src"} component = dmc.Stack( [ dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-tree-view"}, columns=columns, data=build_visible_rows(TREE_DATA, INITIAL_EXPANDED), height=300, sortable=True, ), dcc.Store(id="tree-expanded", data=list(INITIAL_EXPANDED)), dmc.Text( id="tree-output", size="sm", c="dimmed", children="Click chevron to expand/collapse", ), ] ) @callback( Output({"type": "glide-grid", "index": "cells-tree-view"}, "data"), Output("tree-expanded", "data"), Output("tree-output", "children"), Input({"type": "glide-grid", "index": "cells-tree-view"}, "treeNodeToggled"), State("tree-expanded", "data"), State({"type": "glide-grid", "index": "cells-tree-view"}, "data"), prevent_initial_call=True, ) def handle_toggle(toggle_info, expanded, current_data): if not toggle_info: return current_data, expanded, "Click chevron to expand/collapse" expanded_set = set(expanded or []) row_idx = toggle_info["row"] if 0 <= row_idx < len(current_data): node_id = current_data[row_idx]["id"] if toggle_info["isOpen"]: expanded_set.add(node_id) else: expanded_set.discard(node_id) new_data = build_visible_rows(TREE_DATA, expanded_set) return new_data, list(expanded_set), f"Toggled: {toggle_info}" ``` :defaultExpanded: false :withExpandedButton: true #### User Profile Avatar with name display. Use `kind: "user-profile-cell"` with `name`, `initial`, `tint`. .. exec::examples.reference.cell_types.user_profile :code: false ```python # File: examples/reference/cell_types/user_profile.py import dash_glide_grid as dgg columns = [ {"title": "Team Member", "id": "user", "width": 180}, {"title": "Role", "id": "role", "width": 160}, {"title": "Department", "id": "department", "width": 120}, ] data = [ { "user": { "kind": "user-profile-cell", "name": "Alice Johnson", "initial": "A", "tint": "#228be6", }, "role": "Engineering Manager", "department": "Engineering", }, { "user": { "kind": "user-profile-cell", "name": "Bob Smith", "initial": "B", "tint": "#40c057", }, "role": "Senior Developer", "department": "Engineering", }, { "user": { "kind": "user-profile-cell", "name": "Carol Williams", "initial": "C", "tint": "#fab005", }, "role": "Product Designer", "department": "Design", }, { "user": { "kind": "user-profile-cell", "name": "David Brown", "initial": "D", "tint": "#fa5252", }, "role": "DevOps Engineer", "department": "Infrastructure", }, { "user": { "kind": "user-profile-cell", "name": "Emma Davis", "initial": "E", "tint": "#7950f2", }, "role": "Data Scientist", "department": "Analytics", }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-user-profile"}, columns=columns, data=data, height=260, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true #### Spinner Loading spinner indicator. Use `kind: "spinner-cell"` for async operations. .. exec::examples.reference.cell_types.spinner :code: false ```python # File: examples/reference/cell_types/spinner.py import dash_glide_grid as dgg import dash_mantine_components as dmc from dash import callback, Input, Output, State columns = [ {"title": "Task", "id": "task", "width": 160}, {"title": "Status", "id": "status", "width": 100}, {"title": "Result", "id": "result", "width": 120}, ] INITIAL_DATA = [ { "task": "Fetch user data", "status": {"kind": "spinner-cell"}, "result": "Loading...", }, { "task": "Process images", "status": {"kind": "spinner-cell"}, "result": "Loading...", }, { "task": "Generate report", "status": "Queued", "result": "Waiting", }, { "task": "Send notifications", "status": "Queued", "result": "Waiting", }, ] component = dmc.Stack( [ dmc.Button( "Complete First Loading Task", id="complete-spinner-btn", size="compact-sm", variant="light", ), dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-spinner"}, columns=columns, data=INITIAL_DATA, height=240, sortable=True, ), ] ) @callback( Output({"type": "glide-grid", "index": "cells-spinner"}, "data"), Input("complete-spinner-btn", "n_clicks"), State({"type": "glide-grid", "index": "cells-spinner"}, "data"), prevent_initial_call=True, ) def complete_task(n_clicks, data): if not data: return data for row in data: if isinstance(row.get("status"), dict) and row["status"].get("kind") == "spinner-cell": row["status"] = "Complete" row["result"] = "Success" break return data ``` :defaultExpanded: false :withExpandedButton: true #### Sparkline Mini charts (line, area, bar). Use `kind: "sparkline-cell"` with `values`, `graphKind`, `yAxis`, `color`. Add `displayValues` for hover labels and `hoverStyle` ("line" or "dot"). .. exec::examples.reference.cell_types.sparkline :code: false ```python # File: examples/reference/cell_types/sparkline.py import dash_glide_grid as dgg import random random.seed(42) def generate_values(base, volatility=10, length=12): """Generate trend data and display labels.""" values = [base] for _ in range(length - 1): change = random.uniform(-volatility, volatility) values.append(max(0, min(100, values[-1] + change))) values = [round(v, 1) for v in values] return values # Pre-generate values so we can create displayValues from them rev_line = generate_values(50, 8) rev_area = generate_values(50, 8) rev_bar = generate_values(50, 15) user_line = generate_values(30, 10) user_area = generate_values(30, 10) user_bar = generate_values(30, 12) err_line = generate_values(15, 5) err_area = generate_values(15, 5) err_bar = generate_values(15, 8) cpu_line = generate_values(60, 15) cpu_area = generate_values(60, 15) cpu_bar = generate_values(60, 20) columns = [ {"title": "Metric", "id": "metric", "width": 100}, {"title": "Line", "id": "line", "width": 140}, {"title": "Area", "id": "area", "width": 140}, {"title": "Bar (dot hover)", "id": "bar", "width": 140}, ] data = [ { "metric": "Revenue", "line": { "kind": "sparkline-cell", "values": rev_line, "displayValues": [f"${int(v)}k" for v in rev_line], # Hover labels "graphKind": "line", "yAxis": [0, 100], "color": "#40c057", }, "area": { "kind": "sparkline-cell", "values": rev_area, "displayValues": [f"${int(v)}k" for v in rev_area], "graphKind": "area", "yAxis": [0, 100], "color": "#40c057", }, "bar": { "kind": "sparkline-cell", "values": rev_bar, "displayValues": [f"${int(v)}k" for v in rev_bar], "graphKind": "bar", "yAxis": [0, 100], "color": "#40c057", "hoverStyle": "dot", # Dot + tooltip instead of vertical line }, }, { "metric": "Users", "line": { "kind": "sparkline-cell", "values": user_line, "displayValues": [str(int(v)) for v in user_line], "graphKind": "line", "yAxis": [0, 100], "color": "#228be6", }, "area": { "kind": "sparkline-cell", "values": user_area, "displayValues": [str(int(v)) for v in user_area], "graphKind": "area", "yAxis": [0, 100], "color": "#228be6", }, "bar": { "kind": "sparkline-cell", "values": user_bar, "displayValues": [str(int(v)) for v in user_bar], "graphKind": "bar", "yAxis": [0, 100], "color": "#228be6", "hoverStyle": "dot", }, }, { "metric": "Errors", "line": { "kind": "sparkline-cell", "values": err_line, "displayValues": [str(int(v)) for v in err_line], "graphKind": "line", "yAxis": [0, 50], "color": "#fa5252", }, "area": { "kind": "sparkline-cell", "values": err_area, "displayValues": [str(int(v)) for v in err_area], "graphKind": "area", "yAxis": [0, 50], "color": "#fa5252", }, "bar": { "kind": "sparkline-cell", "values": err_bar, "displayValues": [str(int(v)) for v in err_bar], "graphKind": "bar", "yAxis": [0, 50], "color": "#fa5252", "hoverStyle": "dot", }, }, { "metric": "CPU %", "line": { "kind": "sparkline-cell", "values": cpu_line, "displayValues": [f"{int(v)}%" for v in cpu_line], # Percentage labels "graphKind": "line", "yAxis": [0, 100], "color": "#7950f2", }, "area": { "kind": "sparkline-cell", "values": cpu_area, "displayValues": [f"{int(v)}%" for v in cpu_area], "graphKind": "area", "yAxis": [0, 100], "color": "#7950f2", }, "bar": { "kind": "sparkline-cell", "values": cpu_bar, "displayValues": [f"{int(v)}%" for v in cpu_bar], "graphKind": "bar", "yAxis": [0, 100], "color": "#7950f2", "hoverStyle": "dot", }, }, ] component = dgg.GlideGrid( id={"type": "glide-grid", "index": "cells-sparkline"}, columns=columns, data=data, height=240, rowHeight=44, sortable=True, ) ``` :defaultExpanded: false :withExpandedButton: true --- *Source: /reference/cell-types* *Generated with dash-improve-my-llms*