Skip to main content
The @googleforcreators/elements package provides core APIs for registering and managing element types in Web Stories. It includes utilities for creating elements, pages, and working with the element type system.

Installation

npm install @googleforcreators/elements

Element Types

Web Stories supports several built-in element types:
import { ELEMENT_TYPES } from '@googleforcreators/elements';

console.log(ELEMENT_TYPES.IMAGE);         // 'image'
console.log(ELEMENT_TYPES.VIDEO);         // 'video'
console.log(ELEMENT_TYPES.TEXT);          // 'text'
console.log(ELEMENT_TYPES.SHAPE);         // 'shape'
console.log(ELEMENT_TYPES.GIF);           // 'gif'
console.log(ELEMENT_TYPES.STICKER);       // 'sticker'
console.log(ELEMENT_TYPES.PRODUCT);       // 'product'
console.log(ELEMENT_TYPES.AUDIO_STICKER); // 'audioSticker'

Media Element Types

import { MEDIA_ELEMENT_TYPES } from '@googleforcreators/elements';

// Returns: ['image', 'video', 'gif', 'product']
const isMediaElement = MEDIA_ELEMENT_TYPES.includes(element.type);

Element Registration

Registering Element Types

import { registerElementType } from '@googleforcreators/elements';
import type { ElementDefinition } from '@googleforcreators/elements';

const customElementDefinition: ElementDefinition = {
  type: 'customElement',
  defaultAttributes: {
    width: 100,
    height: 100,
  },
  // Additional properties
};

registerElementType(customElementDefinition);

Getting Registered Element Types

import { elementTypes } from '@googleforcreators/elements';

// Access all registered element types
const imageElementDef = elementTypes['image'];
const textElementDef = elementTypes['text'];

Utilities

Creating Elements

import { createNewElement, ELEMENT_TYPES } from '@googleforcreators/elements';

// Create a new text element
const textElement = createNewElement(ELEMENT_TYPES.TEXT, {
  x: 50,
  y: 100,
  width: 200,
  height: 50,
  content: 'Hello World',
  font: {
    family: 'Roboto',
  },
});

// Create a new image element
const imageElement = createNewElement(ELEMENT_TYPES.IMAGE, {
  x: 0,
  y: 0,
  width: 640,
  height: 853,
  resource: {
    type: 'image',
    src: 'https://example.com/image.jpg',
    width: 1920,
    height: 1080,
  },
});

Working with Pages

import { createPage, ELEMENT_TYPES } from '@googleforcreators/elements';

// Create a new blank page
const page = createPage();
console.log(page);
// {
//   id: 'unique-id',
//   elements: [],
//   backgroundColor: { color: { r: 255, g: 255, b: 255 } },
//   // ... other default properties
// }

// Create page with custom properties
const customPage = createPage({
  backgroundColor: {
    type: 'solid',
    color: { r: 0, g: 0, b: 0 },
  },
});

Element Utilities

import { getDefinitionForType, ELEMENT_TYPES } from '@googleforcreators/elements';

const imageDefinition = getDefinitionForType(ELEMENT_TYPES.IMAGE);
const textDefinition = getDefinitionForType(ELEMENT_TYPES.TEXT);

// Use definition to understand element capabilities
console.log(imageDefinition.defaultAttributes);

Position & Transform

import { getOffsetCoordinates } from '@googleforcreators/elements';

const element = {
  x: 100,
  y: 200,
  width: 150,
  height: 100,
  rotationAngle: 45,
};

const offset = getOffsetCoordinates(element);
console.log(offset);
// Returns calculated offset based on rotation and position

Constants

Default Background Color

import { DEFAULT_PAGE_BACKGROUND_COLOR } from '@googleforcreators/elements';

const page = {
  backgroundColor: DEFAULT_PAGE_BACKGROUND_COLOR,
  // { type: 'solid', color: { r: 255, g: 255, b: 255 } }
};

Text Element Defaults

import { 
  TEXT_ELEMENT_DEFAULT_FONT,
  BACKGROUND_TEXT_MODE 
} from '@googleforcreators/elements';

// Default font for text elements
const textElement = {
  type: 'text',
  font: TEXT_ELEMENT_DEFAULT_FONT,
  // {
  //   family: 'Roboto',
  //   weights: [100, 300, 400, 500, 700, 900],
  //   service: 'fonts.google.com',
  //   ... font metrics
  // }
};

// Background text modes
const modes = {
  none: BACKGROUND_TEXT_MODE.NONE,       // 'NONE'
  fill: BACKGROUND_TEXT_MODE.FILL,       // 'FILL'
  highlight: BACKGROUND_TEXT_MODE.HIGHLIGHT, // 'HIGHLIGHT'
};

Overlay Types

import { OverlayType } from '@googleforcreators/elements';

const overlays = {
  none: OverlayType.NONE,     // 'none'
  solid: OverlayType.SOLID,   // 'solid'
  linear: OverlayType.LINEAR, // 'linear'
  radial: OverlayType.RADIAL, // 'radial'
};

const element = {
  type: 'image',
  overlay: {
    type: OverlayType.LINEAR,
    // ... overlay properties
  },
};

Multiple Value Constant

import { MULTIPLE_VALUE } from '@googleforcreators/elements';

// Used when multiple elements have different values for a property
const fontFamily = selectedElements.every(
  el => el.font?.family === selectedElements[0].font?.family
) ? selectedElements[0].font?.family : MULTIPLE_VALUE;

if (fontFamily === MULTIPLE_VALUE) {
  console.log('Multiple fonts selected');
}

TypeScript Types

The package exports comprehensive TypeScript types:
import type {
  Element,
  Page,
  Story,
  ElementType,
  ElementDefinition,
  ImageElement,
  TextElement,
  VideoElement,
  ShapeElement,
  GifElement,
  StickerElement,
  ProductElement,
  Media,
  Resource,
  Taxonomies,
} from '@googleforcreators/elements';

// Example usage
function processElement(element: Element) {
  if (elementIs.image(element)) {
    // TypeScript knows element is ImageElement
    console.log(element.resource.src);
  }
}

function processPage(page: Page) {
  page.elements.forEach(element => {
    console.log(`Element ${element.id} at (${element.x}, ${element.y})`);
  });
}

interface StoryData extends Story {
  customField?: string;
}

Complete Example

import {
  createPage,
  createNewElement,
  duplicateElement,
  ELEMENT_TYPES,
  TEXT_ELEMENT_DEFAULT_FONT,
  DEFAULT_PAGE_BACKGROUND_COLOR,
  elementIs,
  getLayerName,
} from '@googleforcreators/elements';
import type { Page, Element } from '@googleforcreators/elements';

// Create a new story page
const page: Page = createPage({
  backgroundColor: DEFAULT_PAGE_BACKGROUND_COLOR,
});

// Add a text element
const headline = createNewElement(ELEMENT_TYPES.TEXT, {
  x: 50,
  y: 100,
  width: 540,
  height: 100,
  content: '<span style="font-weight: 700">My Story Headline</span>',
  font: TEXT_ELEMENT_DEFAULT_FONT,
  fontSize: 48,
  backgroundColor: { color: { r: 0, g: 0, b: 0, a: 0.5 } },
});

// Add an image element
const backgroundImage = createNewElement(ELEMENT_TYPES.IMAGE, {
  x: 0,
  y: 0,
  width: 640,
  height: 853,
  resource: {
    type: 'image',
    mimeType: 'image/jpeg',
    src: 'https://example.com/background.jpg',
    width: 1920,
    height: 1080,
    alt: 'Background Image',
  },
});

// Add elements to page
page.elements = [backgroundImage, headline];

// Duplicate an element
const duplicatedHeadline = duplicateElement(headline);
duplicatedHeadline.y = 250;
duplicatedHeadline.content = '<span style="font-weight: 400">Subheadline</span>';
page.elements.push(duplicatedHeadline);

// Work with elements
page.elements.forEach((element: Element) => {
  const layerName = getLayerName(element);
  console.log(`Layer: ${layerName}`);
  
  if (elementIs.image(element)) {
    console.log(`Image source: ${element.resource.src}`);
  }
  
  if (elementIs.text(element)) {
    console.log(`Text content: ${element.content}`);
    console.log(`Font: ${element.font.family}`);
  }
});

// Create a complete story with multiple pages
const story = {
  storyId: 1,
  title: 'My Web Story',
  pages: [
    page,
    duplicatePage(page), // Duplicate the entire page
  ],
};

console.log(`Created story with ${story.pages.length} pages`);

Build docs developers (and LLMs) love