Skip to main content
The @googleforcreators/story-editor package provides the core Web Stories editor web application. This is a platform-agnostic React component that can be embedded in any web application.

Installation

npm install @googleforcreators/story-editor

Basic Usage

The editor is provided as a React component with extensive configuration options:
import StoryEditor from '@googleforcreators/story-editor';
import { EditorConfigProvider } from '@googleforcreators/story-editor';

function MyApp() {
  const config = {
    storyId: 123,
    isRTL: false,
    apiCallbacks: {
      // Define your API endpoints
      saveStory: async (story) => { /* ... */ },
      autoSave: async (story) => { /* ... */ },
    },
    capabilities: {
      hasUploadMediaAction: true,
    },
    // Additional configuration...
  };

  return (
    <StoryEditor config={config}>
      {/* Editor interface will render here */}
    </StoryEditor>
  );
}

Key Exports

Components

StoryEditor (default export)

The main editor component:
import StoryEditor from '@googleforcreators/story-editor';

Dialog

Dialog component for modals:
import { Dialog } from '@googleforcreators/story-editor';

InterfaceSkeleton

Layout skeleton for the editor interface:
import { InterfaceSkeleton } from '@googleforcreators/story-editor';

Tooltip

Tooltip component:
import { Tooltip } from '@googleforcreators/story-editor';

Context Providers

EditorConfigProvider

Provides configuration to the editor:
import { EditorConfigProvider } from '@googleforcreators/story-editor';

function App() {
  return (
    <EditorConfigProvider config={config}>
      {/* Your components */}
    </EditorConfigProvider>
  );
}

FontContext

Manages font loading and usage:
import FontContext from '@googleforcreators/story-editor';
import { useContext } from 'react';

function MyComponent() {
  const { getFontByName } = useContext(FontContext);
  const font = getFontByName('Roboto');
}

SidebarContext

Manages sidebar state:
import SidebarContext, { useSidebar } from '@googleforcreators/story-editor';

function MyComponent() {
  const { isSidebarOpen, toggleSidebar } = useSidebar();
}

Utilities

getStoryPropsToSave

Prepares story data for saving:
import { getStoryPropsToSave } from '@googleforcreators/story-editor';

const propsToSave = getStoryPropsToSave(storyData);

useLoadFontFiles

Hook for loading font files:
import { useLoadFontFiles } from '@googleforcreators/story-editor';

function MyComponent() {
  const loadFontFiles = useLoadFontFiles();
  
  useEffect(() => {
    loadFontFiles([
      { family: 'Roboto', url: 'https://...' }
    ]);
  }, [loadFontFiles]);
}

getInUseFontsForPages

Extracts fonts used across pages:
import { getInUseFontsForPages } from '@googleforcreators/story-editor';

const fonts = getInUseFontsForPages(pages);

useIsUploadingToStory

Hook to check upload status:
import { useIsUploadingToStory } from '@googleforcreators/story-editor';

function MyComponent() {
  const isUploading = useIsUploadingToStory();
  
  if (isUploading) {
    return <LoadingSpinner />;
  }
}

Theme & Styling

theme (default export)

The editor theme object:
import { theme } from '@googleforcreators/story-editor';
import { ThemeProvider } from 'styled-components';

function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* Your components */}
    </ThemeProvider>
  );
}

GlobalStyle

Global styles component:
import { GlobalStyle } from '@googleforcreators/story-editor';

function App() {
  return (
    <>
      <GlobalStyle />
      {/* Your app */}
    </>
  );
}

focusStyle

Focus style helper:
import { focusStyle } from '@googleforcreators/story-editor';
import styled from 'styled-components';

const Button = styled.button`
  ${focusStyle}
`;

Highlights

Editor highlighting system:
import { useHighlights, highlightStates, highlightStyles } from '@googleforcreators/story-editor';

function MyComponent() {
  const { setHighlight } = useHighlights();
  
  const handleClick = () => {
    setHighlight({
      elementId: '123',
      state: highlightStates.HOVER
    });
  };
}

Configuration

The editor accepts a comprehensive configuration object:
interface EditorConfig {
  storyId: number;
  isRTL?: boolean;
  flags?: Record<string, boolean>;
  apiCallbacks: {
    saveStory: (story: Story) => Promise<Story>;
    autoSave: (story: Story) => Promise<Story>;
    getMedia: (params: MediaParams) => Promise<Media[]>;
    uploadMedia: (file: File) => Promise<Media>;
    // ... other callbacks
  };
  capabilities: {
    hasUploadMediaAction: boolean;
    hasPublishAction: boolean;
    // ... other capabilities
  };
  styleConstants?: {
    leftOffset?: number;
    topOffset?: number;
  };
  // ... additional config
}

Dependencies

The story editor depends on several other @googleforcreators packages:
  • @googleforcreators/animation - Animation support
  • @googleforcreators/design-system - UI components
  • @googleforcreators/elements - Element types
  • @googleforcreators/fonts - Font management
  • @googleforcreators/media - Media handling
  • And more (see package.json for full list)

TypeScript

The package includes TypeScript definitions:
import type { StoryPropTypes } from '@googleforcreators/story-editor';
import StoryEditor from '@googleforcreators/story-editor';

const config: EditorConfig = {
  // Type-safe configuration
};

Example: Complete Setup

import StoryEditor, { 
  GlobalStyle, 
  theme,
  EditorConfigProvider 
} from '@googleforcreators/story-editor';
import { ThemeProvider } from 'styled-components';

function StoryEditorApp() {
  const config = {
    storyId: 123,
    isRTL: false,
    apiCallbacks: {
      saveStory: async (story) => {
        const response = await fetch('/api/stories', {
          method: 'POST',
          body: JSON.stringify(story),
        });
        return response.json();
      },
      autoSave: async (story) => {
        // Implement auto-save
      },
      getMedia: async ({ searchTerm, pageToken }) => {
        const response = await fetch(
          `/api/media?search=${searchTerm}&page=${pageToken}`
        );
        return response.json();
      },
      uploadMedia: async (file) => {
        const formData = new FormData();
        formData.append('file', file);
        const response = await fetch('/api/media', {
          method: 'POST',
          body: formData,
        });
        return response.json();
      },
    },
    capabilities: {
      hasUploadMediaAction: true,
      hasPublishAction: true,
    },
  };

  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <StoryEditor config={config} />
    </ThemeProvider>
  );
}

Build docs developers (and LLMs) love