name: strapi-ui-design description: Create polished, accessible Strapi v5 plugin admin interfaces using the Strapi Design System exclusively. Use this skill when building, revamping, or refactoring plugin admin pages including settings pages, custom panels, modals, forms, tables, and dashboards. Also invoke when the user mentions Strapi design guidelines, Layouts, LayoutHeader, LayoutContent, Main, Box, or any Strapi Design System components. allowed-tools: Read, Grep, Glob, Edit, Write, WebFetch, mcp__context7__resolve-library-id, mcp__context7__query-docs
This skill guides creation of production-grade Strapi v5 plugin interfaces using the Strapi Design System v2 exclusively. Implement real working code with exceptional attention to consistency, accessibility, and Strapi's visual language.
The user provides admin interface requirements: a settings page, data table, form, modal, dashboard, or custom panel. They may include context about the plugin's purpose and user workflow.
Live Documentation Verification (Context7)
You have access to Context7 for verifying component APIs and patterns against the latest Strapi Design System documentation.
When to query Context7:
- Before using a Design System component whose props you're uncertain about
- When the user asks about a component not covered in the bundled patterns
- When checking for new or renamed components in the latest DS version
- When verifying compound component slot patterns (Field.Root, Modal.Root, Dialog.Root, etc.)
Pre-resolved library IDs (skip resolve-library-id for these):
/strapi/design-system— Strapi Design System v2 component docs/strapi/documentation— Official Strapi v5 docs (for admin hooks likeuseFetchClient,useNotification,Layouts,Page)
Example queries:
query-docs("/strapi/design-system", "Table component props columns rows")— verify Table APIquery-docs("/strapi/design-system", "Field compound component Label Hint Error")— check Field patternquery-docs("/strapi/design-system", "Modal Root Content Header Body Footer")— verify Modal slotsquery-docs("/strapi/documentation", "admin panel useFetchClient useNotification hooks")— check admin hooks
Important: The patterns in this skill's patterns.md and examples.md are your primary reference. Use Context7 to supplement and verify, not as a first resort — it adds latency. Prefer the bundled patterns for common operations.
For the exact API of an individual component (props, compound sub-components, gotchas, and the symbols that no longer exist in v2), consult component-catalog.md — a reference derived directly from the @strapi/design-system v2.2.1 source. Reach for it before Context7 when you just need to confirm a prop name or which sub-components a compound exposes.
Design Thinking for Strapi Admin
Before coding, understand the context and commit to a CONSISTENT Strapi experience:
- Purpose: What does this interface help the admin accomplish? What content or settings does it manage?
- Workflow: Is this a create/read/update/delete flow? A configuration page? A dashboard overview?
- Integration: How does this fit within Content Manager? Is it a sidebar panel, standalone page, or modal?
- Data Density: Is this data-heavy (tables, lists) or action-focused (forms, settings)?
CRITICAL: Strapi admin interfaces must feel native to Strapi. Users should not notice they're using a plugin - it should feel like a core feature. Consistency over creativity.
Then implement working code (React + TypeScript) that is:
- Built exclusively with
@strapi/design-systemcomponents - Accessible and keyboard-navigable
- Consistent with Strapi's visual language
- Properly integrated with React Query and Strapi admin hooks
Strapi Design System v2 Guidelines
Component Library (46 Components)
Full per-component API reference: component-catalog.md.
Layout & Structure:
Main- Page wrapper with proper paddingBox- Flexible container with spacing propsFlex- Flexbox containerGrid.Root/Grid.Item- CSS Grid layoutsDivider- Visual separatorCard- Elevated content container
Page Shell (from @strapi/strapi/admin):
Page.Main- Top-level admin page wrapper (includes loading/error boundary)Page.Title- Sets document title (preferred over<title>)Page.Error- Renders the admin-standard error pagePage.NoPermissions- Renders the admin-standard "no access" pagePage.Loading- Renders the admin-standard loading statePage.Protect- Permission gate, pair withuseRBAC()
Layouts (from @strapi/strapi/admin):
Layouts.Root- Main layout wrapperLayouts.Header- Page header with title/subtitle/actionsLayouts.Content- Main content area with proper paddingLayouts.Action- Action buttons slot in the header
Prefer Page.Main + Layouts.* over hand-rolled <Main> + <Box> wrappers — they ensure consistency with Strapi's core pages.
Typography:
Typography- Text with variant prop (alpha, beta, omega, pi, sigma, epsilon, delta)- Use
variant="alpha"for page titles - Use
variant="beta"for section headers - Default color is
currentColor
Forms & Inputs:
Field- Wrapper for form controls (provides label, hint, error)TextInput- Single-line textTextarea- Multi-line textNumberInput- Numeric valuesDatePicker/TimePicker/DateTimePicker- Date/time selectionSelect- Single selection dropdownCombobox- Searchable dropdownCheckbox/Radio- Boolean/choice inputsToggle/Switch- On/off togglesJSONInput- JSON editing
Buttons & Actions:
Button- Primary actions (variant: default, secondary, tertiary, danger, success)IconButton- Icon-only actionsTextButton- Text link-style buttonLinkButton- Button that navigates
Feedback & Status:
Alert- Contextual messages (variant: default, success, warning, danger)Badge- Status indicatorsStatus- Inline status with iconLoader- Loading spinnerProgressBar- Progress indication
Navigation:
Tabs- Tabbed navigationSubNav- Secondary navigationBreadcrumbs- Location hierarchyLink/BaseLink- Navigation linksPagination- Page navigation
Overlays & Dialogs:
Modal- Dialog windows (Root, Content, Header, Body, Footer)Dialog- Confirmation dialogsPopover- Floating contentTooltip- Hover hints
Data Display:
Table/Thead/Tbody/Tr/Td/Th- Data tablesRawTable- Unstyled table baseAccordion- Collapsible sectionsAvatar- User/entity imagesTag- Categorical labelsEmptyStateLayout- No-data states
Menu & Selection:
SimpleMenu- Dropdown menusSearchbar- Search input with icon
Import Pattern
Always use root imports:
// CORRECT
import {
Button,
TextInput,
Typography,
Box,
Field,
Modal,
} from '@strapi/design-system';
import { Plus, Pencil, Trash } from '@strapi/icons';
// WRONG - Never use path imports
import { Button } from '@strapi/design-system/Button';
Provider Setup
import { DesignSystemProvider } from '@strapi/design-system';
// Already provided by Strapi admin - don't wrap again in plugins
Spacing & Layout
Base font-size is 62.5% (10px), so 1rem = 10px:
<Box padding={8}> {/* 80px padding */}
<Box paddingTop={4}> {/* 40px padding-top */}
<Flex gap={2}> {/* 20px gap */}
Common spacing values: 1, 2, 3, 4, 5, 6, 7, 8, 10 (multiply by 10 for px)
Form Pattern with Field API
<Field.Root name="title" error={errors.title}>
<Field.Label>Title</Field.Label>
<TextInput
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<Field.Hint>Enter a descriptive title</Field.Hint>
<Field.Error />
</Field.Root>
Data Fetching Pattern
Always use React Query with Strapi's useFetchClient:
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useFetchClient, useNotification, useAPIErrorHandler } from '@strapi/strapi/admin';
const { get, post, put, del } = useFetchClient();
const { toggleNotification } = useNotification();
const { formatAPIError } = useAPIErrorHandler();
Permission-Gated UI
Use useRBAC() for admin-side permission checks. Wrap protected routes with Page.Protect:
import { useRBAC, Page } from '@strapi/strapi/admin';
const { allowedActions: { canRead, canUpdate } } = useRBAC({
read: [{ action: 'plugin::my-plugin.read', subject: null }],
update: [{ action: 'plugin::my-plugin.update', subject: null }],
});
Anti-Patterns to Avoid
| Anti-Pattern | Correct Approach |
|---|---|
| Custom styled-components | Use Box, Flex, Grid with props |
Inline styles (style={{...}}) |
Use spacing/color props |
| Custom colors / hex codes | Use theme colors via props |
| Native HTML buttons | Use Button, IconButton, TextButton |
| Native HTML inputs | Use TextInput, Select, Checkbox |
| Custom modals | Use Modal.Root + Modal.Content + Modal.Header + Modal.Body + Modal.Footer |
ModalLayout / ModalHeader / ModalBody / ModalFooter |
REMOVED in DS v2 (absent from v2.2.1 source) — use Modal.Root/Content/Header/Title/Body/Footer |
Layouts / Page from @strapi/design-system |
Import from @strapi/strapi/admin — the DS does not export them |
Tooltip description prop |
Deprecated — use label |
Th action prop |
Deprecated — pass as children |
NumberInput onChange |
Use onValueChange(value: number | undefined) |
alert() or console.* for UX |
Use useNotification() hook |
window.confirm |
Use Dialog component |
| Custom loading spinners | Use Loader component |
| Hardcoded spacing | Use spacing scale (1–10) |
Raw Badge with backgroundColor/textColor |
Prefer Status for semantic status (success/danger/warning), use Badge only for non-semantic tags |
Hand-rolled <Main> + page header |
Use Page.Main + Layouts.Header + Layouts.Content |
Page Structure Template
import { Main, Box, Typography, Button, Flex } from '@strapi/design-system';
import { Plus } from '@strapi/icons';
const MyPluginPage = () => {
return (
<Main>
{/* Header */}
<Box paddingLeft={10} paddingRight={10} paddingTop={8} paddingBottom={6}>
<Flex justifyContent="space-between" alignItems="center">
<Typography variant="alpha">Page Title</Typography>
<Button startIcon={<Plus />}>Add New</Button>
</Flex>
</Box>
{/* Content */}
<Box paddingLeft={10} paddingRight={10}>
{/* Your content here */}
</Box>
</Main>
);
};
Visual Consistency Rules
- Page titles: Always
variant="alpha"Typography - Section headers: Always
variant="beta"Typography - Primary actions:
Button(default variant) - Secondary actions:
Button variant="secondary" - Destructive actions:
Button variant="danger" - Page padding:
paddingLeft={10} paddingRight={10}for main content - Section spacing:
marginBottom={6}between sections - Card padding:
padding={6}inside cards - Form field gaps:
gap={4}between form fields - Table actions:
IconButtonwith Tooltip
Accessibility Requirements
- All interactive elements must be keyboard accessible
- Use
Field.Labelfor all form inputs - Provide
Field.Hintfor complex inputs - Use
aria-labelon IconButton components - Modal focus should trap inside when open
- Use
Statuscomponent for dynamic status changes - Announce loading states with
LiveRegions
Remember: The goal is seamless integration with Strapi's admin experience. A well-designed plugin interface is invisible - it just works exactly as users expect.
For detailed component patterns, see patterns.md. For complete interface examples, see examples.md.