Automated summary
Guides UI work in a Backstage repository by explaining when to reach for the new bui design system (@backstage/ui) versus the legacy core-components and Material UI v4 layers.
Strengths
- Clarifies the coexistence of three UI layers (bui, core-components, MUI v4) with an explicit priority rule
- Documents the setup already in place (backstage:^ dependency, one-time global CSS import, no BUIProvider)
- Points to reliable sources (Backstage Storybook, the shared InfoCard wrapper, the tables skill) instead of guessing at props
Limitations
- Heavily tied to the described Giantswarm/Backstage repository, so it is barely reusable elsewhere
- The provided file is truncated: the section on reading Storybook source is incomplete
- Does not enumerate detailed bui component props, deferring to external verification
Use it whenever creating or changing a page, card, layout, button, or any other frontend component in this Backstage repository.
Avoid it for frontend projects that use neither Backstage nor this bui design system, or for in-depth table work that belongs to the tables skill.
Security analysis
SafeThe skill is documentation for frontend UI conventions. Its curl examples only fetch public Backstage Storybook/GitHub source read-only; there are no destructive commands, secret exfiltration, obfuscated payloads, or safety-disabling instructions.
No concerns found
How this analysis is madeExamples
Add a cluster status card to the gs plugin using the shared InfoCard wrapper built on @backstage/ui, with a header action button.This page currently uses only @backstage/core-components and MUI v4 — which parts can I move to @backstage/ui and which must stay legacy?Does bui have a Menu component and what props does MenuItem take? Help me confirm against the Backstage Storybook source.name: ui description: How to build UI in this repo — the bui (@backstage/ui) design system vs legacy @backstage/core-components + MUI v4, which to reach for, and how to read Backstage Storybook component/story source. Use when creating or changing pages, cards, layouts, buttons, or any frontend component.
The three UI layers in this repo
| Layer | Import from | Status |
| --- | --- | --- |
| bui — the new Backstage design system | @backstage/ui (aka "Backstage UI", "BUI") | Preferred for new work. The direction we're migrating toward. |
| core-components — classic Backstage components | @backstage/core-components | Legacy but still required where bui has no equivalent (e.g. feature-rich Table, Page/Header/Content scaffolding, Link with route refs). |
| Material UI v4 | @material-ui/core | Legacy primitives + makeStyles. Used for styling and gaps bui doesn't cover. MUI v4 docs. |
Rule of thumb: reach for bui first. Fall back to core-components / MUI v4 only
when bui lacks the piece you need. Mixing all three in one file is normal and
expected during the migration — see ClusterAboutCard.tsx, which imports Grid
from bui, Link from core-components, and Box/Tooltip from MUI v4 together.
@backstage/ui is currently 0.16.0 — a young, fast-moving package. APIs change
between releases and it is not a full replacement for core-components yet.
When unsure whether a bui component exists or what props it takes, check the
Storybook source (see below) rather than guessing.
bui setup (already done)
- The plugin's
package.jsonmust declare"@backstage/ui": "backstage:^"(already present ings,ui-react,ai-chat, andapp). - The global stylesheet is imported once in
packages/app/src/index.tsx:import '@backstage/ui/css/styles.css';. Don't re-import it per component. - We do not wrap the app in
BUIProvider— bui components render against the existing app theme + the global CSS. (Storybook recipes useBUIProviderbecause they render in isolation; the real app doesn't need it.)
bui components we actually use
Common primitives already in the codebase (import from @backstage/ui):
- Layout:
Flex,Grid,Box,Container - Surfaces:
Card,CardHeader,CardBody,CardFooter - Typography:
Text(e.g.<Text as="h3" variant="title-x-small" weight="bold">) - Controls:
Button,ButtonIcon,Switch,Link - Overlay/menu:
Tooltip,TooltipTrigger,MenuTrigger,Menu,MenuItem - Data display:
Table+Cell/CellText/ColumnConfig,List,ListRow,Avatar - Page chrome:
PluginHeader,Header(the two-tier header pattern — plugin-levelPluginHeaderabove an entity-levelHeader). NFS page headers andSubPageBlueprinttabs are rendered by the customGSPageLayoutswappable component, not directly — see "Page headers and tabs" indocs/ui.mdbefore building a tabbed page.
Cards: use the shared InfoCard wrapper
@giantswarm/backstage-plugin-ui-react exports an InfoCard built on bui's
Card/CardHeader/CardBody/CardFooter with our standard title styling and
header/footer action slots. Prefer it over hand-rolling a bui Card or the
core-components InfoCard for new cards. Source:
plugins/ui-react/src/components/InfoCard/InfoCard.tsx.
Tables: see the tables skill
The bui Table (data-driven columnConfig + data, cells must return
Cell/CellText) and the feature-rich core-components Table are both
documented in depth in the tables skill, including the choice matrix and
gotchas (loading skeleton needs data={undefined}). Read that skill for anything
table-related; don't duplicate it here.
Reading Backstage Storybook source
The Backstage Storybook renders components
from the upstream backstage/backstage monorepo — stories are .stories.tsx
files colocated with their components. There is no separate storybook repo,
and we do not run a local storybook. To learn a pattern (how a page/card is
composed, what props a bui component takes), read the story + component source
directly.
The reliable technique: index.json → importPath → GitHub raw
Every Storybook deployment publishes a machine-readable index at
https://backstage.io/storybook/index.json. Each entry carries the exact source
paths:
{
"id": "recipes-pluginheader-and-header--with-tabs",
"title": "Recipes/PluginHeader and Header",
"importPath": "./packages/ui/src/recipes/PluginHeaderAndHeader.stories.tsx",
"componentPath": "./packages/ui/src/components/PluginHeader/PluginHeader.tsx"
}
Then fetch the raw source from GitHub (strip the leading ./):
BASE=https://raw.githubusercontent.com/backstage/backstage/master
curl -sfL "$BASE/packages/ui/src/recipes/PluginHeaderAndHeader.stories.tsx"
curl -sfL "$BASE/packages/ui/src/components/PluginHeader/PluginHeader.tsx"
To find the story ID for a Storybook URL: the ?path=/story/<id> query param
is the entry id. Story IDs can drift between releases (the "Recipes/..."
example also now exists as "Backstage UI/PluginHeader") — search index.json by
title or a keyword rather than trusting an old URL. Quick lookup:
curl -sfL https://backstage.io/storybook/index.json \
| jq '.entries | to_entries[] | select(.value.title|test("PluginHeader";"i")) | .value | {id,importPath,componentPath}'
Live inspection with Chrome DevTools
Use the chrome-devtools MCP when you want to inspect the rendered result
(DOM, computed styles, a11y tree) or grab index.json without CORS friction:
new_page/navigate_pagetohttps://backstage.io/storybook/evaluate_scriptrunningfetch('https://backstage.io/storybook/index.json')(same-origin, so no CORS block) to pull the index or any raw story texttake_snapshotfor the a11y tree of a rendered story
Note: the chrome-devtools MCP has its own filesystem roots — it can't write into
the session scratchpad. Fetch text via evaluate_script and return it inline, or
just curl the GitHub raw URL from Bash instead.
Related skills
tables— buiTablevs core-componentsTable, columns, filtering, faceted sidebars.components— component directory structure, named exports, barrel files.upstream-search— searching a local clone ofbackstage/backstage(needsBACKSTAGE_UPSTREAM_DIRset; the Storybook technique above needs no clone).
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/ui-development-in-backstage-mrwak8ze' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/ui-development-in-backstage-mrwak8ze/download' --output '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md.part' && mv '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md.part' '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && test -s '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/ui' && cp -R '.skill-downloads/ui-development-in-backstage-mrwak8ze' '.claude/skills/ui'Cursor
test -f '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && test -s '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/ui' && cp -R '.skill-downloads/ui-development-in-backstage-mrwak8ze' '.cursor/skills/ui'Codex
test -f '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && test -s '.skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/ui' && cp -R '.skill-downloads/ui-development-in-backstage-mrwak8ze' '.agents/skills/ui'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/ui-development-in-backstage-mrwak8ze'openskills read 'ui-development-in-backstage-mrwak8ze'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/ui-development-in-backstage-mrwak8ze/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.