Theme overrides without changing another store's behavior
Select configured, starter, or empty hero content for a theme while preserving cleared editor values and the base Store's behavior.
In this guide
- Trusted theme
- Preserved content contract
- Selected renderer
- Scoped presentation
- Base-store regression
A local improvement becomes a global regression
One store needs a purchasing dashboard instead of the standard hero. A developer changes a shared component and verifies the requested store. Another store now receives the same empty dashboard because it has no supporting account configuration. The change was scoped visually in the developer's mind, but not in the code.
Treat a theme override as a boundary for behavior as well as CSS. Shared components can affect navigation, defaults, data loading, validation, and saved content. A style namespace alone cannot prevent a theme-specific data request or fallback rule from running in another store.
Identify what the theme actually owns
List the intended differences: typography, layout, widget presentation, optional capabilities, or content defaults. Keep business rules such as authorization and price calculation outside purely visual selection. A theme may present a purchasing capability, but should not grant it.
Locate the target SDK's supported registration seam and identify the base behavior to preserve. Prefer composition around a narrow renderer over copying a large vendor component into the custom theme. Copies make upgrades harder because later fixes in the original no longer reach the duplicated implementation automatically.
Select a theme-owned view model
Call selectHero from the theme's registered renderer. SavedHero contains editor content, TrustedTheme contains a capability from trusted theme configuration, and HeroModel describes what to render: configured content, the purchasing starter, or an empty state.
An existing heading, including an empty string, wins over defaults. Only a missing or null heading allows the purchasingStarter capability to supply starter content. Keep account authorization in the server path; enabling a theme presentation does not grant purchasing permission.
theme/select-hero-model.ts typescript
export type SavedHero = Readonly<{
heading?: string | null; actionLabel?: string | null; actionPath?: string | null;
}>;
export type HeroModel = Readonly<{
kind: "configured" | "starter" | "empty";
heading: string; actionLabel: string; actionPath: string;
}>;
export type TrustedTheme = Readonly<{ purchasingStarter: boolean }>;
export function selectHero(saved: SavedHero, theme: TrustedTheme): HeroModel {
if (saved.heading !== undefined && saved.heading !== null) {
return {
kind: "configured", heading: saved.heading,
actionLabel: saved.actionLabel ?? "", actionPath: saved.actionPath ?? ""
};
}
if (theme.purchasingStarter) {
return {
kind: "starter", heading: "Your purchasing workspace",
actionLabel: "View resources", actionPath: "/resources"
};
}
return { kind: "empty", heading: "", actionLabel: "", actionPath: "" };
}
const cleared = selectHero({ heading: "" }, { purchasingStarter: true });
if (cleared.kind !== "configured" || cleared.heading !== "")
throw new Error("An intentionally cleared heading must remain cleared.");
const base = selectHero({}, { purchasingStarter: false });
if (base.kind !== "empty") throw new Error("Base theme must retain its empty state.");
// Map trusted theme selection in the installed theme configuration.
// Render local links through the same URL policy used by ResourcePanel.
With heading '' and purchasingStarter true, the result remains configured with an empty heading. The editor's cleared value is respected. With no saved heading and purchasingStarter true, the result is starter. With no saved heading and the capability false, the result is empty. Register this renderer under the existing saved component key in the theme's override-component-list.
Preserve the saved contract
A theme can change how a widget looks without changing the identity of its saved component. When extending fields, preserve supported existing properties and define how old configurations behave. Defaults should fill missing content according to policy, not overwrite intentional empty values on every render.
Test the editor and storefront together. A custom registration in one application can make preview look correct while the other still uses a different renderer. Record both application artifacts and the selected store theme with release evidence. Shared source files do not guarantee the deployed applications contain the same code.
Compare the base and custom stores
Use two fictional stores: one on the base theme and one on the custom theme. Render the same saved widget in both, then test the custom empty state. Verify that the base store retains its existing behavior and does not request theme-specific data.
Include old saved configurations, configured standard content, missing optional fields, and invalid links. Check narrow layouts and keyboard interaction in both stores. If a shared component was changed, run the relevant base behavior checks as well as the new custom case. Do not equate a successful custom screenshot with absence of regressions elsewhere.
- Scope styles under a deliberate theme root.
- Keep capability checks separate from user permissions.
- Preserve saved component keys unless a migration is explicit.
- Avoid duplicating vendor code without a maintenance reason.
Leave an upgrade trail
Record the purpose of each override, the original component or registration it uses, and the expected fallback. Link those decisions to the base-Store and custom-Store checks so an upgrade reviewer can see which behavior must survive.
During an SDK upgrade, compare the target component contract and registration with that record. A matching filename does not establish compatibility. This small maintenance record is what lets a custom theme remain distinctive without turning every shared-component change into an investigation.
References and further reading
Independent guidance from GCG. Znode is a trademark of its owner. Examples use fictional data and are not official platform documentation. Suggest a correction.