| name | create-component |
| description | Create a new BEEQ StencilJS web component. Use for: scaffolding bq-* components, adding new design system elements, generating component files (TSX, SCSS, types, stories, tests). Follows BEEQ component structure, naming conventions, JSDoc requirements, Shadow DOM, and Nx monorepo placement under packages/beeq/src/components/. |
| argument-hint | Component name without the bq- prefix (e.g. "slider") |
Create a BEEQ Component
When to Use
- Adding a new
bq-* web component to the design system
- Scaffolding all required files for a component from scratch
- Resuming work on an in-progress component scaffold
Before You Start
- Read the instruction files for this task:
- Pick a similar existing component as a reference:
- Simple / display:
packages/beeq/src/components/badge/bq-badge.tsx
- Interactive with events:
packages/beeq/src/components/button/bq-button.tsx
- Form-associated:
packages/beeq/src/components/checkbox/bq-checkbox.tsx
- Compound (host + item):
packages/beeq/src/components/accordion/ + accordion-group/
Procedure
1. Run the Plop generator
pnpm g
Answer the prompts: component name (no bq- prefix), whether to add styling, style variables, and Storybook files. This creates the scaffolded files. Then update the generated e2e.ts extension to .e2e.tsx.
2. Implement the component (bq-<name>.tsx)
Follow the exact section order — do not reorder:
1. Own Properties (private fields, element refs like prefixElem)
2. @Element() (host HTML element reference)
3. @State() (alphabetical, inlined decorator)
4. @Prop() (public API, reflect: true for styling-related props)
5. @Watch() (prop lifecycle validators)
6. @Event() (with full JSDoc; EventEmitter<T>)
7. Component lifecycle (connectedCallback → componentWillLoad → componentDidLoad → disconnectedCallback)
8. @Listen() (event listeners)
9. Public @Method() (async, with full JSDoc)
10. Private local methods (private arrow functions, e.g. private handleClick = () => {})
11. render() (always last)
When defining boolean props, match the type to the intended API shape:
- Use
prop: boolean = false when the prop is conceptually required in the component API and strict TypeScript initialization should guarantee a boolean value internally.
- Use
prop?: boolean when undefined is meaningful in the public API; in that case, do not also assign = false.
3. Create the types file (bq-<name>.types.ts)
Export type aliases and const arrays so both the component and Storybook can use them:
export type TMyComponentSize = 'small' | 'medium' | 'large';
export const MY_COMPONENT_SIZE = ['small', 'medium', 'large'] as const;
Only create this file if the component has typed props. The constant array is used in @Watch validators.
4. Write the component-level JSDoc block
Place above @Component({}). Every component must include:
5. Style the component (scss/bq-<name>.scss)
- Import variables file:
@import './bq-<name>.variables'
- Use Tailwind
@apply for abstracting long utility combinations
- Define CSS custom properties (e.g.
--bq-name--border-radius) in bq-<name>.variables.scss
- Follow BEM for any extra class names
6. After all files are created and implemented, ask the user:
Ask the user:
- What public props does this component need, and which are required?
- Does it need form association (
formAssociated: true)?
- What events should it emit, and what detail payloads do they carry?
- What named slots does it expose beyond the default?
- What are the accessibility requirements — role, ARIA attributes, keyboard interactions?
- Should it support any size, appearance, or variant props?
Then run review-component on the new component to confirm everything is in order.
7. Verify the scaffold
Verify that the build passes without errors:
pnpm exec nx run beeq:build
Key Rules
| Rule | Detail |
|---|
| Tag | bq-<name> — kebab-case, bq- prefix |
| Class | Bq<Name> — PascalCase |
| Events | camelCase, bq prefix (e.g. bqClick, bqChange) |
| Private | private keyword — never # (not supported by Stencil) |
| Local methods | Must be private arrow functions |
| Public methods | Must be async |
| Boolean props | Use prop: boolean = false for required booleans; use prop?: boolean only when undefined is part of the API, and do not combine it with = false |
| Prop validation | Use validatePropValue() from ../../shared/utils + @Watch() |
| Form components | Use @AttachInternals() + formAssociated: true |
| Focus delegation | Use shadow: { delegatesFocus: true } for interactive elements |