SuperAPI AI Directory

using-backstage-ui

Frontend & websites

View repository

Updated 10-16 02:23

About this skill

Backstage UI (BUI) Patterns

When to use this skill

  • Authoring or editing any frontend component in a Backstage plugin
  • Picking the right component for layout, typography, form input, dialog, menu, tab, table, etc.
  • Styling components (BUI uses CSS modules + design tokens, not makeStyles)
  • Adding icons (use @remixicon/react)

Setup

A new plugin scaffolded with yarn new includes @backstage/ui automatically. If installing manually:

yarn add @backstage/ui @remixicon/react

Then add the stylesheet to your app entry (packages/app/src/index.tsx or similar):

import '@backstage/ui/css/styles.css';

Choose the right component

Need Component Reference
Page layout / wrappers Box, Container, Flex, FullPage, Grid references/components.md
Typography Text references/components.md
Buttons / actions Button, ButtonIcon, ButtonLink references/components.md
Forms TextField, PasswordField, SearchField, Select, Combobox, Checkbox, RadioGroup, Switch, DatePicker, DateRangePicker references/components.md
Feedback Alert, Skeleton, Tooltip, Tag, TagGroup references/components.md
Overlays Dialog, Menu, Popover references/components.md
Navigation Tabs, Header, PluginHeader, Link references/components.md
Data Table (+ useTable hook), List (+ ListRow), Avatar, Card references/components.md
Icons @remixicon/react (e.g. RiSearchLine, RiAddLine) references/icons.md
Styling CSS modules with BUI tokens (--bui-space-*, --bui-fg-*, --bui-bg-*) references/styling.md

Two invocation modes

  • Standalone (mid-development): user is editing an existing plugin component. Pick the relevant reference and apply.
  • Post-scaffold (called by creating-backstage-plugin for any frontend template): apply BUI defaults to the freshly scaffolded plugin's example component, ensuring imports come from @backstage/ui and styles use CSS modules with BUI tokens.

Common gotchas

  • BUI ≠ Material UI. Don't mix prop names: disabled → isDisabled; variant="contained" → variant="primary".
  • Flex uses justify="between" (NOT space-between); gap goes via inline style or BUI tokens.
  • Tooltip requires TooltipTrigger as a parent.
  • TextField's onChange receives a string directly, not an event object.
  • One known fallback where BUI doesn't have an equivalent: @material-ui/lab Timeline has no BUI replacement. Use MUI in that specific case.

Data fetching convention

Don't manually wire useState for loading/error/data. Use react-use hooks:

  • useAsync(fn, deps) — runs the async function on mount and whenever deps change. Use for "load data when the component renders or its props change."
  • useAsyncFn(fn) — returns [state, callback]. Use for "load data when the user does X" (button click, form submit, etc.).

Manual useState for { loading, error, value } is an anti-pattern in this codebase: it duplicates logic the hook handles correctly (race conditions, unmount-during-fetch, etc.). The catalog and identity references show useAsync; the same applies anywhere data is fetched.

import useAsyncFn from 'react-use/lib/useAsyncFn';
import { Button, Skeleton, Alert, Text } from '@backstage/ui';

export const FetchOnDemand = () => {
  const [{ loading, error, value }, fetch] = useAsyncFn(async (id: string) => {
    return await someApi.get(id);
  }, []);

  return (
    <>
      <Button onClick={() => fetch('foo')}>Fetch</Button>
      {loading && <Skeleton width={200} height={20} />}
      {error && <Alert status="danger" title={error.message} />}
      {value && <Text>{value.name}</Text>}
    </>
  );
};