A powerful and flexible table card for Home Assistant that combines live data sources with editable columns and persistent storage. Perfect for task management, scheduling, inventory tracking, and any scenario requiring dynamic, user-editable tables.
-
๐ Three Operating Modes:
- Sensor Mode: Sync with live data sources (Todoist, Calendar, custom integrations)
- Standalone Mode: Pure editable table with persistent storage
- Content-Only Mode: Display sensor data without storage requirements
-
๐ Rich Column Types:
- Text: Simple text input
- Number: Numeric input with optional min/max/step controls
- Dropdown: Select from predefined options
- Cycle: Click to cycle through options
- Checkbox: Boolean toggle
- Date: Date picker with formatting
- Content: Display-only columns from data sources
- Split Display: Split text/content on delimiters for multi-line display (e.g., addresses)
-
๐ฅ User-Based Access Control:
- Table-level and column-level editability
- Specify which Home Assistant users can edit
- Mix editable and read-only columns
-
๐๏ธ Safe Row Deletion:
- Confirmation dialog before deleting rows
- Prevents accidental data loss
-
๐จ Customization:
- Custom CSS styling support
- Markdown top/bottom content areas
- Responsive design with mobile support
- Configurable header visibility
- Optional friendly name display
-
โก Smart Row Management:
- Add rows above/below
- Delete rows with confirmation
- Move rows up/down
- Actions column with intuitive controls
-
๐พ Persistent Storage:
- JSON-based storage in
/config/www/ - Automatic file creation on first edit
- Command-line sensor integration
- Not required for content-only tables
- JSON-based storage in
- Open HACS in Home Assistant
- Go to "Frontend"
- Click the three dots menu (top right) and select "Custom repositories"
- Add this repository URL:
https://github.com/pgorod/PowerTable - Select category: "Lovelace"
- Click "Add"
- Find "Power Table Card" and click "Install"
- Restart Home Assistant
- Download
powertable-card.jsfrom the latest release - Copy it to
/config/www/(create thewwwfolder if it doesn't exist) - Add the resource to your Lovelace configuration:
lovelace:
mode: yaml
resources:
- url: /local/powertable-card.js
type: module- Restart Home Assistant
Perfect for displaying sensor data without storage requirements.
1. Configure Lovelace Resource (in configuration.yaml):
lovelace:
mode: yaml
resources:
- url: /local/powertable-card.js
type: module2. Add the Card to Your Dashboard:
type: custom:powertable-card
friendly_name: Device Status # Optional - omit to hide header
show_header: true # Only shows if friendly_name is set
data_source:
type: sensor_attribute
entity_id: sensor.my_devices
attribute_path: devices # Can be nested: parent.child.data
primary_key: id
columns:
- name: ID
type: content
source: id
hidden: true
- name: Device Name
type: content
source: name
- name: Status
type: content
source: status
- name: Last Seen
type: content
source: last_seenNote: When all columns are content type (read-only sensor data), no storage sensor or JSON file is needed!
Perfect for simple editable tables without external data sources.
1. Configure Lovelace Resource (in configuration.yaml):
lovelace:
mode: yaml
resources:
- url: /local/powertable-card.js
type: module2. Create a Command-Line Sensor:
Add to your configuration.yaml:
command_line:
- sensor:
name: table_storage_shopping_list
command: 'cat /config/www/table_storage_shopping_list.json'
value_template: "{{ now().isoformat() }}"
json_attributes:
- row_data
scan_interval: 303. Create a Shell Command for Saving:
Add to your configuration.yaml:
shell_command:
save_table_data: "/config/save_table_data.sh '{{ table_data }}' '{{ file_path }}'"4. Create the Save Script:
Create /config/save_table_data.sh:
#!/bin/bash
echo "$1" > "$2"Make it executable:
chmod +x /config/save_table_data.sh5. Add the Card to Your Dashboard:
type: custom:powertable-card
standalone_mode: true
entity: sensor.table_storage_shopping_list
friendly_name: Shopping List
path_to_storage_json: /config/www/table_storage_shopping_list.json
editable: [john, mary] # Replace with your HA usernames
show_header: true
columns:
- name: Item
type: text
- name: Quantity
type: number
min: 1
max: 99
step: 1
- name: Priority
type: dropdown
options: [Low, Medium, High]
- name: Purchased
type: checkbox6. Restart Home Assistant
That's it! You now have a fully functional editable shopping list. The table will automatically create the JSON file on first edit.
Ideal for syncing with live data sources like Todoist, Google Calendar, or custom integrations.
1-4. Follow steps 1-4 from Standalone Mode above
5. Create a Data Source Sensor:
This example uses a Todoist sensor (requires Todoist integration):
command_line:
- sensor:
name: table_storage_todoist
command: 'cat /config/www/table_storage_todoist.json'
value_template: "{{ now().isoformat() }}"
json_attributes:
- row_data
scan_interval: 306. Add the Card with Data Source Configuration:
type: custom:powertable-card
entity: sensor.table_storage_todoist
friendly_name: My Todoist Tasks
show_header: true
path_to_storage_json: /config/www/table_storage_todoist.json
editable: [john, mary] # Users who can edit
if_missing: hide # What to do with rows missing from source
data_source:
type: sensor_attribute
entity_id: sensor.all_todoist_items # Your Todoist sensor
attribute_path: items
primary_key: id # Field to match rows
columns:
# Hidden column for matching (not displayed)
- name: ID
type: content
source: id
hidden: true
# Read-only columns from data source
- name: Task
type: content
source: content
- name: Due
type: content
source: due_date
# Editable columns (inherit table-level permissions)
- name: My Notes
type: text
- name: Priority
type: dropdown
options: [Low, Medium, High]
editable: [john] # Override: only john can edit
- name: Status
type: cycle
options: [Not Started, In Progress, Done]
- name: Hours Spent
type: number
min: 0
max: 24
step: 0.57. Restart Home Assistant
This creates a hybrid table: live task data from Todoist with your own editable columns for notes, priorities, and tracking!
| Property | Type | Default | Description |
|---|---|---|---|
type |
string | Required | custom:powertable-card |
entity |
string | Conditional | Sensor entity containing table storage (not required for content-only tables) |
standalone_mode |
boolean | false |
Enable standalone mode (no data source) |
friendly_name |
string | - | Display name for the table (optional - header only shows if both show_header and friendly_name are set) |
path_to_storage_json |
string | Conditional | Path to JSON storage file (e.g., /config/www/table.json) - not required for content-only tables |
show_header |
boolean | true |
Show table header row |
editable |
array/boolean | true |
Users allowed to edit. true = all users, false = none, [user1, user2] = specific users |
if_missing |
string | show |
Behavior for rows missing from data source: remove, hide, disable, show |
fit_width |
boolean | false |
Make table fit container width |
accent |
string | - | Accent color for styling |
sort_column |
string | - | Name of column to sort by on load (e.g., "Priority") |
sort_direction |
string | asc |
Initial sort direction: 'asc' (ascending) or 'desc' (descending) |
style |
string | - | Custom CSS styles |
markdown_top_content |
string | - | Markdown content above table (supports templates) |
markdown_bottom_content |
string | - | Markdown content below table (supports templates) |
columns |
array | Required | Column definitions (see below) |
You can set a default sort order using sort_column and sort_direction.
Sorting Logic by Column Type:
| Column Type | Ascending (asc) |
Descending (desc) |
|---|---|---|
| Text/Content | A โ Z (alphabetical) | Z โ A (reverse alphabetical) |
| Number | Smallest โ Largest | Largest โ Smallest |
| Date | Oldest โ Newest | Newest โ Oldest |
| Checkbox | Unchecked, then Checked | Checked, then Unchecked |
| Dropdown/Cycle | Order of options list | Reverse order of options list |
Example:
type: custom:powertable-card
sort_column: "Priority" # Sort by Priority column
sort_direction: 'desc' # Highest priority firstdata_source:
type: sensor_attribute
entity_id: sensor.your_data_source
attribute_path: items # Path to array/dict in sensor attributes (supports nested paths: parent.child.data)
primary_key: id # Field used to match rowsSupported Data Formats:
- Array:
[{id: 1, name: "Item1"}, {id: 2, name: "Item2"}] - Dictionary/Object:
{key1: {name: "Item1"}, key2: {name: "Item2"}}(auto-converts to array, adds_keyfield) - String: Automatically parsed as JSON if needed
Nested Paths: Use dot notation for nested attributes:
attribute_path: akuvox_map.map # Accesses sensor.attributes.akuvox_map.map- name: Notes
type: text
editable: [user1, user2] # Optional: override table-level- name: Address
type: text
split: "," # Splits "123 Main St,Apt 4B" into two lines
# Useful for displaying multi-part data like addresses, codes, or timestamps- name: Quantity
type: number
min: 0
max: 100
step: 1
editable: true- name: Status
type: dropdown
options: [Todo, In Progress, Done]
editable: [john]- name: Priority
type: cycle
options: [Low, Medium, High]- name: Completed
type: checkbox- name: Due Date
type: date
format: "yyyy-mm-dd" # Optional: custom format- name: Task Name
type: content
source: content # Field name from data source
hidden: false # Optional: hide column but keep for matching| Property | Type | Default | Description |
|---|---|---|---|
name |
string | Required | Column header text |
type |
string | Required | Column type: text, number, dropdown, cycle, checkbox, date, content |
editable |
array/boolean | Inherit | Override table-level editability for this column |
hidden |
boolean | false |
Hide column (useful for ID columns) |
min_width |
string | - | Minimum column width (e.g., "150px" or "20%") |
style |
string | - | Custom CSS for this column (applies to both header and data cells) |
source |
string | - | Data source field (for content type) |
options |
array | - | Available options (for dropdown/cycle types) |
min |
number | - | Minimum value (for number type) |
max |
number | - | Maximum value (for number type) |
step |
number | - | Increment step (for number type) |
format |
string | "yyyy-mm-dd" |
Date format (for date type) |
split |
string | - | Character to split on for multi-line display (for text/content types) |
When all visible columns are of type content, the table operates in pure read-only mode and does not require:
- โ Storage entity (
entityparameter) - โ JSON file (
path_to_storage_json) - โ Shell command configuration
- โ Command-line sensor
This is perfect for displaying sensor data without any persistence needs.
Example:
type: custom:powertable-card
# No entity or storage needed!
data_source:
type: sensor_attribute
entity_id: sensor.my_data
attribute_path: items
primary_key: id
columns:
- name: Name
type: content
source: name
- name: Value
type: content
source: valueUse the style property to add custom CSS:
type: custom:powertable-card
entity: sensor.table_storage_tasks
style: |
.power-table th {
color: white !important;
background: linear-gradient(to right, #667eea, #764ba2) !important;
}
.readonly-cell {
background: #f0f0f0 !important;
font-style: italic;
}
.actions-cell {
background: #e3f2fd !important;
}Apply custom CSS to individual columns using the style property. The styling applies to both the column header (th) and all data cells (td) in that column.
Example:
type: custom:powertable-card
entity: sensor.table_storage_tasks
columns:
- name: Priority
type: dropdown
options: [Low, Medium, High, Urgent]
style: |
background: #fff3cd;
font-weight: bold;
color: #856404;
- name: Status
type: cycle
options: [Todo, In Progress, Done]
style: |
text-align: left;
font-style: italic;
- name: Hours
type: number
style: |
background: linear-gradient(to right, #e3f2fd, #bbdefb);
font-family: monospace;Common Use Cases:
- Highlight important columns: Background colors, bold text
- Custom alignment:
text-align: left/center/right - Typography: Font family, size, weight, style
- Visual separation: Borders, gradients, shadows
- Conditional emphasis: Colors based on column purpose
Note: Column-level styling takes precedence over table-level styles for that specific column.
Add context above/below your table using Home Assistant templates:
markdown_top_content: |
**Weekly Schedule**
๐ค Editing as: **{{ user }}** | ๐
{{ states('sensor.date') }}
*Click cells to edit. Long press for advanced actions.*
markdown_bottom_content: |
Last updated: {{ now().strftime('%Y-%m-%d %H:%M') }}
๐ง Questions? Contact: admin@example.comtype: custom:powertable-card
standalone_mode: true
entity: sensor.table_storage_tasks
friendly_name: Team Task Board
path_to_storage_json: /config/www/table_storage_tasks.json
editable: [manager, team_lead]
show_header: true
sort_column: "Priority"
sort_direction: 'desc'
accent: '#4CAF50'
markdown_top_content: |
**Sprint Tasks** | Editing as: **{{ user }}**
๐ฏ Focus: Complete all High priority items this week
columns:
- name: Task
type: text
min_width: "200px"
- name: Assigned To
type: dropdown
options: [John, Mary, Alex, Sarah, Mike, '']
- name: Priority
type: cycle
options: [Low, Medium, High, Urgent]
- name: Status
type: dropdown
options: [Backlog, In Progress, Review, Done]
- name: Hours
type: number
min: 0
max: 40
step: 0.5
- name: Due Date
type: date
- name: Completed
type: checkbox
editable: true # Everyone can mark completetype: custom:powertable-card
standalone_mode: true
entity: sensor.table_storage_inventory
friendly_name: Office Inventory
path_to_storage_json: /config/www/table_storage_inventory.json
editable: [admin, office_manager]
fit_width: true
sort_column: "Quantity"
sort_direction: 'asc'
style: |
.power-table {
font-size: 13px;
}
.power-table td {
padding: 6px;
}
columns:
- name: Item
type: text
min_width: "150px"
- name: Category
type: dropdown
options: [Electronics, Furniture, Supplies, Other]
- name: Quantity
type: number
min: 0
max: 999
- name: Low Stock
type: checkbox
- name: Last Ordered
type: date
- name: Supplier
type: text
- name: Notes
type: text
min_width: "200px"type: custom:powertable-card
entity: sensor.table_storage_todoist
friendly_name: Enhanced Todoist View
path_to_storage_json: /config/www/table_storage_todoist.json
editable: [john, mary]
if_missing: hide # Hide completed/deleted tasks
show_header: true
sort_column: "Due"
sort_direction: 'asc'
data_source:
type: sensor_attribute
entity_id: sensor.all_todoist_items
attribute_path: items
primary_key: id
markdown_top_content: |
**My Enhanced Tasks** ({{ user }})
Data synced from Todoist with custom tracking columns
columns:
# From Todoist (read-only)
- name: ID
type: content
source: id
hidden: true
- name: Task
type: content
source: content
min_width: "200px"
- name: Project
type: content
source: project_name
- name: Due
type: content
source: due_date
# Custom editable columns
- name: My Priority
type: cycle
options: [P4, P3, P2, P1]
- name: Time Estimate
type: number
min: 0.25
max: 8
step: 0.25
- name: Progress
type: dropdown
options: [Not Started, Started, Blocked, Almost Done]
- name: My Notes
type: text
min_width: "200px"
- name: Reviewed
type: checkbox- Ensure the sensor entity exists and is not
unavailable - Check browser console for errors
- Verify the resource is properly loaded in Lovelace
- Verify
/config/save_table_data.shexists and is executable - Check
shell_commandis properly configured - Ensure
/config/www/directory has write permissions - Check Home Assistant logs for errors
- Ensure the JSON file path is correct
- Verify command-line sensor is properly configured
- Restart Home Assistant after configuration changes
- Check that usernames in
editablematch your Home Assistant users - Username comparison is case-sensitive
- Use Developer Tools โ States to verify current user
- Verify
data_source.entity_idexists - Check
attribute_pathmatches your sensor's structure - Ensure
primary_keyfield exists in source data - Set appropriate
if_missingbehavior
- Check if
attribute_pathexists using Developer Tools โ States - For nested paths, use dot notation:
parent.child.data - Verify data is an array or object/dictionary format
- Check browser console for parsing errors
- Ensure
primary_keyfield exists in your data items
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by various Home Assistant table cards and mindmup's editable table
- Built with Lit Element
- Uses marked for Markdown rendering
- Date formatting by Steven Levithan
- ๐ Report bugs
- ๐ก Request features
- ๐ฌ Community forum
Made with โค๏ธ for the Home Assistant community
