Component generators for Summon - React and Svelte component scaffolding
npm install @canonical/summon-componentComponent scaffolding for React and Svelte projects. Generates production-ready component structures with TypeScript, tests, stories, and styles — all following consistent conventions.
Creating a new component by hand means creating 5-7 files with boilerplate that's almost identical every time. This generator handles that in one command, ensuring:
- Consistent file structure across your codebase
- Proper TypeScript types from the start
- Test files that actually test something
- Storybook stories ready to customize
- Auto-registration in your component barrel
``bash`
bun add @canonical/summon-component
Requires @canonical/summon as a peer dependency:
`bash`
bun add @canonical/summon
Or link globally for use across projects:
`bash`
cd /path/to/summon-component
bun link # for bun
npm link # for npm
---
`bashInteractive — prompts guide you
summon component react
$3
`bash
Interactive
summon component svelteDirect
summon component svelte --component-path=src/lib/components/CardWith TypeScript stories instead of Svelte CSF
summon component svelte --component-path=src/lib/components/Card --use-ts-stories
`---
What Gets Generated
$3
For
summon component react --component-path=src/components/Button:`
src/components/Button/
├── Button.tsx # Component implementation
├── types.ts # Props interface
├── index.ts # Barrel export
├── Button.test.tsx # Unit tests (Testing Library)
├── Button.ssr.test.tsx # SSR tests (optional)
├── Button.stories.tsx # Storybook stories (optional)
└── styles.css # Component styles (optional)
`And appends to
src/components/index.ts:`typescript
export * from "./Button";
`#### Generated Component
`tsx
// Button.tsx
import type { ButtonProps } from "./types";
import "./styles.css";export const Button = ({
className,
children,
...props
}: ButtonProps): JSX.Element => {
return (
button${className ? ${className} : ""}} {...props}>
{children}
);
};
`#### Generated Types
`typescript
// types.ts
import type { HTMLAttributes, PropsWithChildren } from "react";export interface ButtonProps
extends PropsWithChildren> {}
`#### Generated Test
`tsx
// Button.test.tsx
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { Button } from "./Button";describe("Button", () => {
it("renders children", () => {
render();
expect(screen.getByText("Hello")).toBeInTheDocument();
});
it("applies custom className", () => {
render();
expect(screen.getByText("Content")).toHaveClass("custom");
});
});
`$3
For
summon component svelte --component-path=src/lib/components/Card:`
src/lib/components/Card/
├── Card.svelte # Svelte 5 component with runes
├── types.ts # Props interface
├── index.ts # Barrel export
├── Card.svelte.test.ts # Unit tests
├── Card.ssr.test.ts # SSR tests (optional)
├── Card.stories.svelte # Storybook CSF (optional)
└── styles.css # External styles (optional, or inline
`Uses Svelte 5 runes (
$props()) and render tags (@render).---
Options Reference
$3
| Flag | Description | Default |
|------|-------------|---------|
|
--component-path | Full path for the component (e.g., src/components/Button) | Interactive prompt |
| --with-styles | Include styles.css file | true |
| --no-with-styles | Skip styles file | — |
| --with-stories | Include Storybook stories | true |
| --no-with-stories | Skip stories file | — |
| --with-ssr-tests | Include SSR test file | true |
| --no-with-ssr-tests | Skip SSR tests | — |$3
| Flag | Description | Default |
|------|-------------|---------|
|
--component-path | Full path for the component (e.g., src/lib/components/Card) | Interactive prompt |
| --with-styles | Include inline