Core Storybook UI - React based UI components that provide the core interface for Storybook
—
The provider system is the core abstraction that allows consumers to customize and configure the Storybook UI. It consists of a base Provider class that must be extended, along with React components for custom implementations. The Provider class uses concrete methods that throw errors rather than abstract methods.
Base class that defines the interface for providing UI elements, handling API initialization, and supplying configuration. All methods throw errors by default and must be implemented by subclasses.
/**
* Base class for Storybook UI providers
* All consumers must extend this class to use the Storybook UI
*/
class Provider {
/**
* Get UI elements by type - must be implemented by subclasses
* @param type - Type identifier for the UI elements to retrieve (from @storybook/addons Types enum)
* @returns Object containing UI elements for the specified type
* @throws Error with message "Provider.getElements() is not implemented!" if not overridden
*/
getElements(type: Types): any;
/**
* Handle API initialization - must be implemented by subclasses
* @param api - The Storybook API instance
* @throws Error with message "Provider.handleAPI() is not implemented!" if not overridden
*/
handleAPI(api: unknown): void;
/**
* Return configuration object - has default implementation that returns empty object
* @returns Configuration object for the Storybook UI
* @note Logs error "Provider.getConfig() is not implemented!" but doesn't throw, returns {}
*/
getConfig(): any;
}Usage Examples:
import { Provider } from "@storybook/ui";
class MyProvider extends Provider {
private stories = [];
private config = { theme: 'light' };
getElements(type) {
// Must implement - will throw error if not overridden
switch (type) {
case 'TAB':
return {
component: MyTabComponent,
props: { stories: this.stories }
};
case 'PANEL':
return {
component: MyPanelComponent,
props: { theme: this.config.theme }
};
case 'TOOL':
return {
component: MyToolComponent,
props: { addons: this.getAddons() }
};
default:
return {};
}
}
handleAPI(api) {
// Must implement - will throw error if not overridden
console.log('API initialized:', api);
// Initialize stories if available
if (this.stories.length > 0) {
api.setStories(this.stories);
}
}
getConfig() {
// Optional - has default implementation that returns {}
return {
theme: this.config.theme,
showNav: true,
showPanel: true
};
}
private getAddons() {
return [
{ name: 'controls', component: ControlsAddon },
{ name: 'actions', component: ActionsAddon }
];
}
}
// Example showing error behavior if methods not implemented
class IncompleteProvider extends Provider {
// Missing getElements and handleAPI implementations
}
const incomplete = new IncompleteProvider();
try {
incomplete.getElements('TAB'); // Throws: "Provider.getElements() is not implemented!"
} catch (error) {
console.error(error.message);
}
try {
incomplete.handleAPI({}); // Throws: "Provider.handleAPI() is not implemented!"
} catch (error) {
console.error(error.message);
}
// getConfig() doesn't throw, but logs error and returns {}
const config = incomplete.getConfig(); // Logs: "Provider.getConfig() is not implemented!"
console.log(config); // {}React functional component that serves as the entry point for the Storybook UI application, wrapping the entire interface with necessary providers.
/**
* Root component for the Storybook UI application
* @param props - RootProps containing provider and optional history
*/
const Root: FunctionComponent<RootProps>;
interface RootProps {
/** Provider instance that supplies UI elements and configuration */
provider: Provider;
/** Optional browser history instance for routing (currently unused in implementation) */
history?: History;
}Implementation Details:
Usage Examples:
import { Root, Provider } from "@storybook/ui";
class CustomProvider extends Provider {
getElements(type) {
// Must implement
return { component: MyComponent };
}
handleAPI(api) {
// Must implement
console.log('API ready');
}
}
// Basic usage (most common pattern)
function App() {
const provider = new CustomProvider();
return <Root provider={provider} />;
}
// With history parameter (currently unused by implementation)
function AppWithHistory() {
const provider = new CustomProvider();
const history = createBrowserHistory(); // Not currently used by Root component
return <Root provider={provider} history={history} />;
}Note: The history prop is included in the interface but is not currently used by the Root component implementation. This may be for future compatibility or legacy reasons.
All Provider subclasses must implement the following methods:
class MyProvider extends Provider {
// REQUIRED: Must override, throws error otherwise
getElements(type: Types) {
// Return UI elements for the given type
// Types include: 'TAB', 'PANEL', 'TOOL', 'TOOLEXTRA', 'PREVIEW', 'NOTES_ELEMENT'
return {};
}
// REQUIRED: Must override, throws error otherwise
handleAPI(api: unknown) {
// Handle API initialization and setup
console.log('API initialized');
}
// OPTIONAL: Has default implementation that returns {}
getConfig() {
// Return configuration for the UI
return {};
}
}type Types = 'TAB' | 'PANEL' | 'TOOL' | 'TOOLEXTRA' | 'PREVIEW' | 'NOTES_ELEMENT';
interface History {
push(path: string): void;
replace(path: string): void;
go(delta: number): void;
back(): void;
forward(): void;
listen(listener: Function): Function;
}Install with Tessl CLI
npx tessl i tessl/npm-storybook--ui