| name | add-component |
| description | Scaffold a new custom Decentraland component under src/components/<Name>/. Triggers on "add a <Name> component", "new component in ui2", "ui2 component scaffold". Use whenever a brand-new public component is being added to the library. |
add-component
Adds a new component to src/components/<Name>/ following the conventions in CLAUDE.md §3 and the patterns established by the 39 existing components (Button, EventSmallCard, JumpIn, Badges, …).
When to use
- Adding a brand-new public component (
Address, EventSmallCard, …).
- Forking an existing MUI component into a themed DCL counterpart.
When NOT to use
- Re-exporting an existing raw MUI component without customization → just edit
src/index.ts (see CLAUDE.md §11).
- Adding an internal-only helper → put it in
src/lib/ or src/utils/, not src/components/.
- Editing files under
src/@mui/ — those are generated by bin/storybookGenerator.ts (see CLAUDE.md §12).
Steps
1. Create the component directory
mkdir -p src/components/<Name>
2. Write the 4 required files
src/components/<Name>/<Name>.types.ts:
import { ReactNode } from 'react'
import { <Name>Props as MuiBaseProps } from '@mui/material'
interface <Name>Props extends Omit<MuiBaseProps, '<removed-keys>'> {
}
export type { <Name>Props }
src/components/<Name>/<Name>.tsx:
import { <Name>Props } from './<Name>.types'
export const <Name> = ({ /* destructured props */, ...rest }: <Name>Props) => {
return (
)
}
src/components/<Name>/index.ts:
export type { <Name>Props } from './<Name>.types'
export { <Name> } from './<Name>'
src/components/<Name>/<Name>.stories.tsx:
import { <Name> } from './<Name>'
import { <Name>Props } from './<Name>.types'
import type { Meta, StoryObj } from '@storybook/react'
const meta = {
title: 'Decentraland UI/<Name>',
component: <Name>,
tags: ['autodocs'],
args: { },
argTypes: { }
} satisfies Meta<<Name>Props>
export default meta
type Story = StoryObj<<Name>Props>
export const Default: Story = {}
The title prefix Decentraland UI/ is required — .storybook/preview.ts uses storySort ['Decentraland UI', 'Material UI'].
3. (Optional) Add <Name>.styled.ts for complex styling
If the component has more than ~3 small styled() definitions or any cross-component hover targeting, extract them to a separate file:
src/components/<Name>/<Name>.styled.ts:
import { Box, styled } from '@mui/material'
export const <Name>Container = styled(Box)(({ theme }) => ({
}))
When targeting another styled component from a parent, use data-role attribute selectors, not Emotion component references — this is the recurring gotcha from PR #429. See skill styled-with-mui for the full pattern.
4. Re-export from src/index.ts (if public)
Find the section labelled with the alphabetical neighbours and insert:
export { <Name> } from './components/<Name>'
export type { <Name>Props } from './components/<Name>'
Named exports only — no export *. The bundle's tree-shaking depends on the explicit list (CLAUDE.md §5).
5. Run the pre-PR pipeline
npm run format
npm run lint:fix
npm run lint:package-json
npm run build
npm test
The build is what catches breaking type changes in the published dist/index.d.ts — CI runs it too.
6. (Optional) Verify in Storybook
npm run start
Open http://localhost:6006. Confirm:
- The story renders without console errors.
- The component appears under the
Decentraland UI/ section.
- Theme switching (light/dark via the Storybook toolbar) keeps the component readable.
Common mistakes
- Default export instead of named export — breaks the consumer import pattern.
- Hardcoded hex colors instead of theme tokens — fails dark mode silently.
- Forgetting to re-export from
src/index.ts — the component exists but consumers can't import it.
export * in src/index.ts — breaks tree-shaking; consumers ship dead code.
- Hover targeting another styled component via
${TimePill} instead of [data-role="time-pill"] — see skill styled-with-mui.
- Story
title without the Decentraland UI/ prefix — story appears in the wrong section and the storySort default changes.
References
- CLAUDE.md §3 (component conventions), §5 (public API), §4 (styled gotcha).
- Sibling skill
styled-with-mui for the styled() pattern.
- Sibling skill
pre-pr-pipeline for the verification order.
- Existing components:
src/components/Button/ (simplest 4-file), src/components/EventSmallCard/ (with .styled.ts).