Customization Precedence
TradeScript customization is layered and explicit. When two layers set the same chart property, the later/higher layer wins.

| Precedence | Layer | Notes |
|---|---|---|
| 1 | Runtime calls on chart.customization() | Immediate and highest priority until a later runtime call or restored state changes the same field. |
| 2 | chart.setState(...) and chart.applyLayout(...) | Restored chart state applies state.customization. |
| 3 | initialState.customization | Constructor-time customization for saved state and application defaults. |
| 4 | Constructor options such as theme, locale, and timezone | Used when initialState.customization does not define the same field. |
| 5 | ChartStorageAdapter user settings | User settings are a separate state surface. They do not silently rewrite chart overrides unless host code applies them. |
| 6 | Chart defaults | Built-in chart defaults. |
Visual layer order
That ranking answers where a setting came from. Within the resulting visual state, the layers compose in a different order, lowest first:
| Order | Layer | Supplies |
|---|---|---|
| 1 | Theme (theme / setTheme / applyTheme) | A complete canvas and chrome: candles, grid, axes, crosshair, pane separators, and every --ts-chart-* token. |
| 2 | chartOverrides | Container, main series, panes, scales, grid, axes, sessions, trading overlays. |
| 3 | styleOverrides | Background, crosshair, indicators, drawings, handles, candles, and the low-level styles escape hatch. |
A preset therefore fills in everything, and any override you set explicitly still wins. Only the keys a layer actually sets are emitted, so a partial override never blanks the values beneath it.
Three common conflicts
| Conflict | Winner | Why |
|---|---|---|
| Constructor theme vs restored state theme | Restored state (initialState.customization) | Restored state is applied at a higher layer than constructor options |
| Runtime override vs restored layout vs later runtime call | The most recent runtime call | Layer 1 wins, but a restore in between replaces the field until the next runtime call |
| Theme values vs explicit overrides | The explicit override | chartOverrides and styleOverrides compose above the theme |
Walkthrough 1: constructor theme vs restored state theme
sdk.chart.mount({
mount: '#chart',
symbol: 'AAPL',
interval: '1D',
datafeed,
theme: 'light',
initialState: {
customization: {
theme: 'dark',
},
},
});
- Both layers set the theme: the constructor option says
'light'(layer 4), the seeded customization says'dark'(layer 3). - Winning value:
theme = 'dark'. The chart renders dark from the first paint. - Reason:
initialState.customizationis restored state, and restored state outranks constructor options for the same field. Thetheme: 'light'option would only apply ifinitialState.customizationdid not definetheme.
Walkthrough 2: runtime override vs restored layout vs later runtime call
Assume savedLayout carries customization.chartOverrides.grid.horizontal.color = '#0f172a'.
const ui = chart.customization();
ui.applyOverrides({ grid: { horizontal: { color: '#1f2937' } } });
// grid is now #1f2937 — runtime call, layer 1
await chart.applyLayout(savedLayout);
// grid is now #0f172a — the restore replaced the field, layer 2 applied later
ui.applyOverrides({ grid: { horizontal: { color: '#334155' } } });
// grid is now #334155 — a later runtime call wins again
- Winning value:
grid.horizontal.color = '#334155'. - Reason: runtime calls hold a field only until a later restore or runtime call changes the same field. The restore legitimately overwrote
#1f2937with#0f172a; the final runtime call then took the field back. If your product theme must always win after a layout restore, reapply it afterapplyLayout(...)— see My restored layout uses the old theme.
Walkthrough 3: theme values vs explicit overrides
chart.customization().applyTheme('ocean-depths');
chart.customization().applyOverrides({
mainSeries: { upColor: '#16a34a', downColor: '#dc2626' },
});
- Both layers color the candles: the
ocean-depthspreset supplies its own main-series colors, and the override pins#16a34a/#dc2626. - Winning values:
mainSeries.upColor = '#16a34a',mainSeries.downColor = '#dc2626'. Everything not overridden — background, grid, axes, chrome tokens — adoptsocean-depths. - Reason: within the visual composition,
chartOverridessits above the theme. Switching themes later still keeps the pinned candle colors until the override is cleared; the same holds for candle colors set throughsetCandleColors(...).
Layouts
Layouts carry ChartState, including customization. Applying a layout calls the same state path as setState(...); it does not introduce a second customization authority.
const layout = chart.getLayout('desk-open');
await chart.applyLayout(layout);
User Settings
features.userSettings: true enables load and autosave through the configured storage adapter. The stored UserSettingsState is separate from CustomizationState.
Use user settings for product preferences such as favorite intervals, menu state, or host-defined preferences. Use initialState.customization, applyOverrides(...), applyStyleOverrides(...), and the other customization methods for chart appearance and behavior.
This separation is intentional: customization remains typed and inspectable instead of being silently overridden by browser or server preferences. A stored user preference only affects chart customization when host code reads it and issues a customization call — at which point that call is an ordinary layer-1 runtime call.
Provenance Inspection
Use native snapshot tracking when a host needs to explain which layer last changed a customization field:
const tracker = chart.customization().trackSnapshots('constructor');
chart.customization().applyOverrides({
grid: { horizontal: { color: '#1f2937' } },
});
const inspection = tracker.inspect();
console.table(inspection.effectiveFields);
tracker.dispose();
inspection.effectiveFields lists current leaf fields and the snapshot source that last changed each one. inspection.fieldHistory keeps set/clear history. inspection.fieldApplication reports whether a field is applied, conditional, application-owned, stored-only, or unknown. inspection.diagnostics reports invalid typed values.
For saved-state debugging, use the exported inspectCustomizationSnapshots(...), inspectCustomizationFieldApplication(...), inspectChartDisplaySettingsApplication(...), inspectBuiltInIndicatorDefaults(...), inspectBuiltInIndicatorProperties(...), validateCustomizationState(...), and validateChartDisplaySettings(...) helpers. They accept public state objects and return structured results suitable for logs or support reports.
Related pages
- Customization Troubleshooting — symptom-first fixes for each conflict above.
- Themes — the base layer in this order.
- Overrides — the layer that outranks a theme for the same field.
- User Settings — the separate state surface that never rewrites customization on its own.