Skip to main content
The @googleforcreators/design-system package provides a comprehensive set of React UI components used throughout the Web Stories editor and dashboard. All components are built with TypeScript and styled-components.

Installation

npm install @googleforcreators/design-system

Peer Dependencies

This package requires:
{
  "react": "^17.0.2",
  "react-dom": "^17.0.2",
  "styled-components": "^5.3.11"
}

Components

The design system exports a comprehensive set of UI components:

Buttons

import { Button, ButtonSize, ButtonType, ButtonVariant } from '@googleforcreators/design-system';

function MyComponent() {
  return (
    <>
      <Button
        size={ButtonSize.Medium}
        type={ButtonType.Primary}
        onClick={() => console.log('clicked')}
      >
        Click Me
      </Button>

      <Button
        size={ButtonSize.Small}
        type={ButtonType.Secondary}
        disabled
      >
        Disabled
      </Button>
    </>
  );
}

Button Props

  • size: ButtonSize.Small | ButtonSize.Medium | ButtonSize.Large
  • type: ButtonType.Primary | ButtonType.Secondary | ButtonType.Tertiary | ButtonType.Quaternary
  • variant: ButtonVariant.Rectangle | ButtonVariant.Circle | ButtonVariant.Square
  • disabled: boolean
  • onClick: click handler

Form Controls

import { Input } from '@googleforcreators/design-system';

function MyComponent() {
  const [value, setValue] = useState('');

  return (
    <Input
      value={value}
      onChange={(e) => setValue(e.target.value)}
      placeholder="Enter text..."
      aria-label="Text input"
    />
  );
}

Layout & Navigation

import { Modal } from '@googleforcreators/design-system';

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open Modal</Button>
      
      <Modal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        title="Modal Title"
      >
        <p>Modal content goes here</p>
      </Modal>
    </>
  );
}

Dialog

import { Dialog } from '@googleforcreators/design-system';

function ConfirmDialog({ isOpen, onClose, onConfirm }) {
  return (
    <Dialog
      isOpen={isOpen}
      onClose={onClose}
      title="Confirm Action"
      actions={
        <>
          <Button onClick={onClose}>Cancel</Button>
          <Button type={ButtonType.Primary} onClick={onConfirm}>
            Confirm
          </Button>
        </>
      }
    >
      Are you sure you want to proceed?
    </Dialog>
  );
}
import { Popup, PopupProvider } from '@googleforcreators/design-system';

function App() {
  return (
    <PopupProvider>
      <MyComponent />
    </PopupProvider>
  );
}

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);
  const anchorRef = useRef(null);

  return (
    <>
      <Button ref={anchorRef} onClick={() => setIsOpen(true)}>
        Open Popup
      </Button>
      
      <Popup
        anchor={anchorRef}
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
      >
        Popup content
      </Popup>
    </>
  );
}

ContextMenu

import { 
  ContextMenu, 
  ContextMenuProvider,
  ContextMenuComponents 
} from '@googleforcreators/design-system';

const { Item, Separator, Group } = ContextMenuComponents;

function MyComponent() {
  return (
    <ContextMenuProvider>
      <ContextMenu
        items={[
          <Item onClick={() => console.log('Edit')}>Edit</Item>,
          <Item onClick={() => console.log('Copy')}>Copy</Item>,
          <Separator />,
          <Group label="More Options">
            <Item onClick={() => console.log('Delete')}>Delete</Item>
          </Group>
        ]}
      >
        Right-click me
      </ContextMenu>
    </ContextMenuProvider>
  );
}
import { DropDown } from '@googleforcreators/design-system';

function MyComponent() {
  const [selected, setSelected] = useState('option1');
  
  const options = [
    { value: 'option1', label: 'Option 1' },
    { value: 'option2', label: 'Option 2' },
    { value: 'option3', label: 'Option 3' },
  ];

  return (
    <DropDown
      options={options}
      value={selected}
      onChange={setSelected}
      placeholder="Select option..."
    />
  );
}

Feedback Components

import { SnackbarProvider, useSnackbar } from '@googleforcreators/design-system';

function App() {
  return (
    <SnackbarProvider>
      <MyComponent />
    </SnackbarProvider>
  );
}

function MyComponent() {
  const { showSnackbar } = useSnackbar();

  const handleSave = async () => {
    try {
      await saveData();
      showSnackbar({
        message: 'Saved successfully!',
        dismissable: true,
      });
    } catch (error) {
      showSnackbar({
        message: 'Error saving',
        dismissable: true,
      });
    }
  };

  return <Button onClick={handleSave}>Save</Button>;
}

Progress Indicators

import { LoadingSpinner } from '@googleforcreators/design-system';

function MyComponent() {
  return <LoadingSpinner />;
}

Typography

import { 
  Text, 
  Headline, 
  Display,
  TextSize 
} from '@googleforcreators/design-system';

function MyComponent() {
  return (
    <>
      <Display size={TextSize.Large}>Display Text</Display>
      <Headline size={TextSize.Medium}>Headline</Headline>
      <Text size={TextSize.Small}>Body text</Text>
    </>
  );
}

Utility Components

import { Search } from '@googleforcreators/design-system';

function MyComponent() {
  const [searchTerm, setSearchTerm] = useState('');

  return (
    <Search
      value={searchTerm}
      onChange={(e) => setSearchTerm(e.target.value)}
      placeholder="Search..."
    />
  );
}

Slider

import { Slider } from '@googleforcreators/design-system';

function MyComponent() {
  const [value, setValue] = useState(50);

  return (
    <Slider
      value={value}
      onChange={setValue}
      min={0}
      max={100}
      aria-label="Volume"
    />
  );
}

InfiniteScroller

import { InfiniteScroller } from '@googleforcreators/design-system';

function MyComponent() {
  const loadMore = async () => {
    // Load more items
  };

  return (
    <InfiniteScroller
      onLoadMore={loadMore}
      hasMore={hasMoreItems}
    >
      {items.map(item => <Item key={item.id} {...item} />)}
    </InfiniteScroller>
  );
}

Icons

The design system includes a comprehensive icon set:
import { Icons } from '@googleforcreators/design-system';

function MyComponent() {
  return (
    <>
      <Icons.Checkmark />
      <Icons.Close />
      <Icons.ArrowDown />
      <Icons.Plus />
    </>
  );
}

Theme

Access theme constants and helpers:
import { 
  lightMode,
  THEME_CONSTANTS,
  themeHelpers,
  ThemeGlobals 
} from '@googleforcreators/design-system';
import { ThemeProvider } from 'styled-components';
import styled from 'styled-components';

function App() {
  return (
    <ThemeProvider theme={lightMode}>
      <ThemeGlobals.GlobalStyle />
      <MyComponent />
    </ThemeProvider>
  );
}

// Using theme in styled components
const StyledDiv = styled.div`
  color: ${({ theme }) => theme.colors.fg.primary};
  ${({ theme }) => themeHelpers.focusableOutlineCSS(theme.colors.border.focus)};
`;

Storage Utilities

import { 
  localStore, 
  LOCAL_STORAGE_PREFIX,
  sessionStore,
  SESSION_STORAGE_PREFIX 
} from '@googleforcreators/design-system';

// Local storage
localStore.setItem('key', { data: 'value' });
const data = localStore.getItem('key');

// Session storage
sessionStore.setItem('tempKey', 'value');
const tempData = sessionStore.getItem('tempKey');

Keyboard Navigation

import { 
  useKeyboardNavigation,
  useGridViewKeys 
} from '@googleforcreators/design-system';

function MyList() {
  const { currentIndex, handleKeyDown } = useKeyboardNavigation({
    itemCount: items.length,
    onSelect: (index) => selectItem(items[index]),
  });

  return (
    <div onKeyDown={handleKeyDown}>
      {items.map((item, index) => (
        <div key={item.id} aria-selected={index === currentIndex}>
          {item.name}
        </div>
      ))}
    </div>
  );
}

Accessibility

All components follow accessibility best practices:
  • Proper ARIA attributes
  • Keyboard navigation support
  • Focus management
  • Screen reader support
import { VisuallyHidden } from '@googleforcreators/design-system';

function MyComponent() {
  return (
    <button>
      <Icons.Delete />
      <VisuallyHidden>Delete item</VisuallyHidden>
    </button>
  );
}
Before using modals, you must set the app element for accessibility:
import { setAppElement } from '@googleforcreators/design-system';

setAppElement('#root');

Build docs developers (and LLMs) love