TreeViewFilter
A hierarchical tree-based filter component that allows users to browse, search, and select multiple categories from a nested structure. Perfect for filtering data with hierarchical categories or implementing multi-level navigation.
Features
- Hierarchical category browsing with expandable/collapsible nodes
- Multi-select functionality with checkbox selection
- Real-time search capabilities across all category levels
- "Show selected only" toggle for focused viewing
- Customizable tag display with limiting options
- Comprehensive event tracking system
- Controlled and uncontrolled component modes
- Accessibility support with keyboard navigation
Props
Required Props
| Prop | Type | Description |
|---|---|---|
id | string | Unique identifier for the component (required for Dash callbacks) |
categories | array | Array of category objects with the structure: { id: string, name: string, children?: Category[] } |
Optional Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultSelectedIds | string[] | [] | Initial selected category IDs (uncontrolled mode) |
selectedIds | string[] | [] | Currently selected category IDs (controlled mode) |
isOpen | boolean | false | Controls whether the filter dropdown is open |
label | string | "Categories" | Label text for the component |
placeholder | string | "Select categories..." | Placeholder text when no categories are selected |
searchPlaceholder | string | "Search categories..." | Placeholder text for the search field |
applyButtonText | string | "Apply" | Text for the apply button |
cancelButtonText | string | "Cancel" | Text for the cancel button |
limitTags | number | 2 | Maximum number of tags to display before showing "+N". Set to -1 to show all tags |
collapseIdenticalPaths | boolean | false | Whether to collapse paths with identical names in the hierarchy |
switchLabel | string | "Show selected only" | Label for the "Show selected only" switch |
maxTrackingEvents | number | 100 | Maximum number of events to keep in tracking history |
chipLabelMaxWidth | string | "100px" | Maximum width of the chip label before truncating |
Category Structure
Each category in the categories array should have the following structure:
{
"id": "unique_id",
"name": "Category Name",
"children": [
{
"id": "child_id",
"name": "Child Category",
"children": [...]
},
...
]
}
Events
The component tracks various user interactions through the trackingEvents prop. Each event has the following structure:
{
eventType: string; // Type of event (e.g., "select_item", "search", "apply")
timestamp: number; // Unix timestamp
payload: {
nodeId?: string; // ID of affected node
nodeName?: string; // Name of affected node
searchQuery?: string; // Search query
selectedItems?: string[]; // Selected item IDs
isSelected?: boolean; // Selection state
isExpanded?: boolean; // Expansion state
showSelectedOnly?: boolean; // Show selected only state
}
}
Event types include:
expand_nodecollapse_nodeselect_itemdeselect_itemapplycancelclear_allsearchtoggle_selected_onlyopen_menuclose_menu
Usage Example
import dash
from dash import html
import yipit_dash_mui_components as dmc
app = dash.Dash(__name__)
# Define your category structure
categories = [
{
"id": "electronics",
"name": "Electronics",
"children": [
{
"id": "computers",
"name": "Computers",
"children": [
{"id": "laptops", "name": "Laptops"},
{"id": "desktops", "name": "Desktops"}
]
},
{"id": "phones", "name": "Phones"}
]
},
{
"id": "books",
"name": "Books",
"children": [
{"id": "fiction", "name": "Fiction"},
{"id": "nonfiction", "name": "Non-Fiction"}
]
}
]
app.layout = dmc.YipitMUIProvider(
children=[
html.Div([
dmc.TreeViewFilter(
id="category-filter",
categories=categories,
defaultSelectedIds=[],
selectedIds=["ultrabooks", "gaming_desktops", "headphones"],
isOpen=False,
label="Categories",
placeholder="Select categories...",
searchPlaceholder="Search categories...",
applyButtonText="Apply Filters",
cancelButtonText="Cancel",
limitTags=1,
collapseIdenticalPaths=True,
switchLabel="Show selected only",
maxTrackingEvents=10,
chipLabelMaxWidth="50px" # This will truncate long category names in chips
)
])
]
)
if __name__ == "__main__":
app.run_server(debug=True)
Callback Example
from dash import Input, Output, callback
# Callback to handle selected categories
@callback(
Output("output-div", "children"),
Input("category-filter", "selectedIds")
)
def update_output(selected_ids):
if not selected_ids:
return "No categories selected"
return f"Selected categories: {', '.join(selected_ids)}"
# Callback to track user interactions
@callback(
Output("events-div", "children"),
Input("category-filter", "trackingEvents")
)
def display_events(events):
if not events:
return "No events recorded"
return [
html.Div(f"Event: {event['eventType']} - {event['payload']}")
for event in events
]
Best Practices
- Always provide unique
idprops when using multiple TreeViewFilter components - Use
defaultSelectedIdsfor initial selection, andselectedIdsfor controlled behavior - Consider using
limitTagsto prevent overflow when many items are selected - Use
collapseIdenticalPaths=Truewhen dealing with deep hierarchies that might have repeated names - Monitor
trackingEventsto understand user interaction patterns
Notes
- The component maintains its own state for selections but can also be controlled through props
- Search functionality is case-insensitive and searches through both IDs and names
- The "Show selected only" toggle helps users focus on their selections
- Event tracking is limited by
maxTrackingEventsto prevent memory issues
Performance Considerations
-
Large Category Trees
- For large category structures, consider using
collapseIdenticalPaths - The search function indexes all category names and IDs for quick lookup
- Event tracking is capped by
maxTrackingEventsto prevent memory issues
- For large category structures, consider using
-
Selection Management
- Use controlled mode (
selectedIds) for complex state management - The
limitTagsprop helps manage visual clutter with many selections
- Use controlled mode (