.ai/RENDERER.md
The dash-renderer is the TypeScript/React frontend that powers Dash applications. Located in dash/dash-renderer/src/.
1. DashRenderer constructor
└─ ReactDOM.createRoot('#react-entry-point')
└─ <AppProvider />
2. AppProvider creates Redux store
└─ Registers observers for callback processing
3. APIController fetches from server
├─ GET /_dash-layout → component tree
├─ GET /_dash-dependencies → callback definitions
└─ Dispatches setLayout, setGraphs, setPaths
4. Config includes children_props from ComponentRegistry
└─ Stored in window.__dashprivate_childrenProps
5. hydrateInitialOutputs()
├─ Validates callbacks against layout
├─ Triggers initial callbacks
└─ Sets appLifecycle: 'HYDRATED'
6. DashWrapper renders component tree
The layout is traversed using crawlLayout (actions/utils.js). This algorithm:
props.children if presentchildren_props configEach component class defines _children_props listing props that contain nested components. This is:
_children_propsComponentRegistry.children_props when components are importeddash.py:933)window.__dashprivate_childrenProps on the frontend# Example: Python component class
class Dropdown(Component):
_children_props = ['options.[].label', 'options.[].title']
# ...
| Pattern | Meaning | Example |
|---|---|---|
children | Direct children prop | Standard |
prop.[] | Array items are components | options.[] |
prop.[].sub | sub prop of array items | options.[].label |
prop.{} | Object values are components | Dynamic keys |
prop.{}.sub | sub prop of object values | Nested dynamic |
crawlLayout(object, func, currentPath, extraPath)
// For each component:
// 1. Call func(object, currentPath)
// 2. If props.children exists, crawl it
// 3. For each path in children_props[namespace][type]:
// - Parse the pattern (handle [], {})
// - Crawl that path to find nested components
Components are resolved from window[namespace][type]:
// Component packages register on window
window.dash_html_components = { Div, Span, H1, ... };
window.dash_core_components = { Dropdown, Graph, Input, ... };
// Registry.js resolves {type, namespace} → React component
Registry.resolve({type: 'Div', namespace: 'dash_html_components'})
// → window.dash_html_components.Div
Callbacks are triggered by two sources:
When a component calls setProps, it triggers callbacks watching those props:
// Component calls setProps
this.props.setProps({ value: newValue });
// DashWrapper.tsx handles this:
// 1. dispatch(updateProps(...)) → Updates layout in Redux
// 2. dispatch(notifyObservers(...)) → Finds and queues callbacks
notifyObservers calls includeObservers to find callbacks with matching inputs:
// actions/index.js
export function notifyObservers({id, props}) {
return async function (dispatch, getState) {
const {graphs, paths} = getState();
dispatch(
addRequestedCallbacks(includeObservers(id, props, graphs, paths))
);
};
}
When a callback completes and updates component props, it also triggers dependent callbacks via includeObservers in the executedCallbacks observer.
Once callbacks are added to the queue, observers process them through states:
REQUESTED → PRIORITIZED → EXECUTING → EXECUTED → STORED
↓
WATCHED (promises)
↓
BLOCKED (waiting on deps)
dcc.Loading{
layout: { ... }, // Component tree
layoutHashes: { // Change tracking for memoization
"path": { hash, changedProps }
},
paths: { // ID → path mapping
strs: { "my-id": [...path] },
objs: { "type,index": [...] } // Wildcards
},
callbacks: { // Pipeline states
requested, prioritized, blocked,
executing, watched, executed, stored
},
graphs: { // Dependency graph
inputMap: { "id": { "prop": [callbacks] } }
},
config: {
children_props: { ... }, // From ComponentRegistry
// ...
},
isLoading: boolean
}
Maps component IDs to their location in layout:
// String IDs
paths.strs["my-dropdown"] = ["layout", "props", "children", 2, "props"]
// Wildcard IDs (pattern-matching)
paths.objs["type,index"] = [
{ values: ["filter", 0], path: [...] },
{ values: ["filter", 1], path: [...] }
]
The clientside callback API (utils/clientsideFunctions.ts):
window.dash_clientside = {
no_update, // Return to skip output
PreventUpdate, // Throw to cancel callback
callback_context, // Current callback info
set_props, // Update props from clientside
clean_url, // URL sanitization
Patch // Partial prop updates
}
Available during callback execution:
window.dash_clientside.callback_context = {
triggered: [{ prop_id: "btn.n_clicks", value: 1 }],
triggered_id: "btn",
inputs: { "input.value": "hello" },
states: { "store.data": {...} }
}
// In assets/clientside.js
window.dash_clientside = window.dash_clientside || {};
window.dash_clientside.my_namespace = {
my_function: function(input_value) {
return input_value.toUpperCase();
}
};
Update component props directly from clientside:
// By string ID
window.dash_clientside.set_props('my-component', { value: 'new' });
// By pattern-matching ID
window.dash_clientside.set_props({ type: 'input', index: 0 }, { value: 'new' });
API for components to interact with Dash (dashApi.ts):
window.dash_component_api = {
ExternalWrapper, // Render outside main tree
DashContext, // React Context
useDashContext, // Hook for context
getLayout, // Get props by ID/path
stringifyId // Convert wildcard IDs
}
Retrieve component props:
const props = window.dash_component_api.getLayout('my-dropdown');
// → { id: 'my-dropdown', options: [...], value: 'a' }
Hook for components:
const {
componentPath,
isLoading,
useSelector,
useDispatch
} = useDashContext();
DashWrapper uses hash-based memoization. layoutHashes tracks which components changed:
layoutHashes["0,props,children"] = {
hash: 42, // Increments on change
changedProps: { value: true }
}
Components only re-render when their hash changes.
| File | Purpose |
|---|---|
DashRenderer.js | Entry point |
AppProvider.react.tsx | Redux store setup |
APIController.react.js | Fetches layout, hydrates app |
wrapper/DashWrapper.tsx | Component rendering, setProps |
actions/utils.js | crawlLayout algorithm |
registry.js | Component resolution |
reducers/layout.js | Layout state |
reducers/callbacks.ts | Callback pipeline |
reducers/config.js | Stores children_props |
actions/index.js | notifyObservers |
actions/dependencies_ts.ts | includeObservers, callback matching |
observers/*.ts | Callback processing |
utils/clientsideFunctions.ts | Clientside API |
dashApi.ts | Component API |