How to generate realistic json mock data for storybook stories
- Step 1Map your component props onto the fixed shape — Before generating, note which generated fields you will use: a user-card story might map
name,email,status,score, andaddress.city. The generator always emits the full record; you destructure or rename as needed. - Step 2Set count to match the story type — Use 1 record for a Default/detail story, 8–12 for a card grid, 20–50 for a long list or table. Free plan allows up to 500; Pro up to 10,000 — far more than any single story needs.
- Step 3Lock a seed for snapshot stability — Pick a seed (default
42) and reuse it for that story. Because the data is deterministic, your visual-regression tool will not flag false diffs from changing content. Use distinct seeds for distinct stories so they do not all look identical. - Step 4Generate and copy — Click Generate Mock Data, then Copy. Output is always pretty-printed 2-space JSON. Paste the single object or the array into your story file.
- Step 5Wire it into story args — For a single record:
export const Default: Story = { args: { user: <record> } }. For a list:args: { users: <array> }. Map field names to your prop names if they differ. - Step 6Build edge-case stories by overriding fields — Take a generated record and override one field for each edge case — a very long
namefor overflow, an empty array for the empty state,active: falsefor the disabled variant. The generator gives you the convincing base; you author the extremes.
Generated field → typical Storybook prop mapping
The shape is fixed, so this is how teams usually map it onto component props. Rename fields with json-key-renamer if your prop names differ.
| Generated field | Maps well to | Story use |
|---|---|---|
name | Card title / row primary text | Reveals truncation in fixed-width cells |
email | Secondary text / mailto: link | Safe test domains — clickable in stories |
status | Status chip / badge | Cycles active/inactive/pending/suspended — tests all chip colors |
score | Rating / progress / metric | 0–100 with a decimal — tests numeric formatting |
address.city | Subtitle / location line | From a fixed city pool |
active | Toggle / enabled state | Mix of true/false across records |
createdAt | Timestamp line | YYYY-MM-DD, 2020–2024 — tests date formatting |
Record count by story type
Practical counts. The generator clamps to your plan limit (500 free / 10,000 Pro) but stories rarely need the ceiling.
| Story type | Suggested count | Why |
|---|---|---|
| Default / detail | 1 | Single record into a scalar prop |
| Card grid | 8–12 | Fills a typical viewport without scroll |
| List / feed | 20–50 | Tests scrolling and item separators |
| Table with pagination | 100+ | Exercises page controls (Pro for >500) |
| Empty state | 0 (author manually) | Generator minimum is 1 — pass [] yourself |
Cookbook
Story-ready recipes. Each shows the generated data and where it goes in the story file.
Default story from a single seeded record
ExampleCount 1, seed 42 gives one convincing record. Map the fields you need onto the component's props.
// Generated: count 1, seed 42
const user = {
id: "ab732cc0-86ce-45f2-ad8f-78e93ffbe1ce",
name: "Grace Davis",
email: "grace.davis@mock.dev",
status: "active",
score: 47.1,
address: { city: "Ogdenville" }
};
export const Default: Story = { args: { user } };A card grid that exercises every status color
ExampleBecause status cycles across active, inactive, pending, suspended, a grid of ~10 records naturally shows all chip variants in one story.
// Generated: count 10, seed 42 → import as users[]
import users from './users.json';
export const Grid: Story = {
args: { users },
// The grid renders 10 cards; status chips show all four states
// without you authoring each variant by hand.
};Stable snapshots for visual regression
ExampleThe seed makes Chromatic snapshots deterministic. Reuse one seed per story; never regenerate with a new seed unless you intend the snapshot to change.
// users.json was generated at seed 42 — committed alongside the story. // Chromatic diff stays empty on rebuild because data never changes. // // To intentionally refresh content (and accept new snapshots): // regenerate at a NEW seed, commit, then approve the Chromatic diff.
Overflow edge-case story
ExampleStart from a generated record and override a single field to force the edge case. The generator supplies the realistic base; you author the extreme.
import users from './users.json';
export const LongName: Story = {
args: {
user: {
...users[0],
name: 'Maximiliana Featherstonehaugh-Wellington III'
}
}
};Rename fields to match your prop interface
ExampleIf your component expects fullName and joinedAt, generate the records and rename keys with json-key-renamer before pasting into the story.
Step 1 — generate count 8, seed 42 here.
Step 2 — json-key-renamer: name → fullName, createdAt → joinedAt
Result per record:
{ "id": "...", "fullName": "Grace Davis", "joinedAt": "2024-01-17", ... }Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
You expected to paste your prop interface
Not supportedThe generator does not read TypeScript prop types or PropTypes. It emits the fixed person shape and you map fields onto your props. For mismatched names, run the output through json-key-renamer; to drop unused fields, json-key-filter.
All status chips look the same in a tiny story
ExpectedWith only 1–3 records you may not hit all four status values. To guarantee every chip color appears, generate ~10+ records (status cycles through active/inactive/pending/suspended) or override the field per record for a deliberate variant matrix.
Chromatic flagged a diff after regenerating
By designIf you regenerated at a different seed, the data changed, so the snapshot legitimately differs. Keep one seed per story and commit the generated JSON. Only change the seed when you intend to refresh the story's content.
Need an empty-state story
Author manuallyThe generator's minimum is 1 record — it cannot emit an empty array. For an empty-state story, pass [] yourself: args: { users: [] }. Use the generator for the populated states.
Avatar / image URL needed but not generated
Not generatedThe record has no image field — there is no avatar URL in the output. Add one in the story by deriving from name or id, e.g. a DiceBear or picsum URL keyed on user.id, after pasting the generated data.
Toggling Sequential IDs changed all the card content
By designThe id mode shifts the random stream, so flipping Sequential IDs alters names, ages, and statuses at the same seed. Decide the id style first, then lock the seed for the story.
Output is pretty-printed but you want it inline in args
CosmeticOutput is always 2-space indented. That is fine inside a story file; your formatter (Prettier) will reflow it. If you specifically want minified JSON, pass it through json-minifier first.
Free plan stopped a 1,000-record table story
Plan limitFree caps at 500 records. A pagination story usually needs only enough rows to show two or three pages; if you genuinely need 1,000+, Pro raises the cap to 10,000.
Frequently asked questions
Does the tool read my component's prop types?
No. It emits a fixed person-record shape (id, index, name, email, phone, age, status, nested address, score, createdAt, active) and you map those onto your props. For different prop names, rename with json-key-renamer; to drop fields your component ignores, use json-key-filter.
Will my Storybook snapshots stay stable?
Yes, as long as you keep the same seed for a story. The generator is deterministic — seed 42 always produces the same array — so visual-regression tools like Chromatic see no content drift. Commit the generated JSON next to the story and only change the seed when you intend to refresh the content.
How do I get all four status chip colors in one story?
Generate around ten or more records. The status field cycles through active, inactive, pending, and suspended, so a grid of ten naturally shows every chip variant. For a deliberate one-of-each matrix, override status per record after generating.
Can I generate avatar image URLs?
Not directly — the record has no image field. Derive an avatar in the story from name or id (e.g. a DiceBear or picsum URL seeded by user.id) after pasting the generated data. The generator covers text fields, not media URLs.
How many records should a story use?
One for a Default/detail story, 8–12 for a card grid, 20–50 for a list or feed, 100+ for a paginated table. The generator clamps to 500 on free and 10,000 on Pro, well above any single story's needs.
Can I make an empty-state story with the tool?
No — the minimum is 1 record, so it cannot emit []. Author the empty state by passing an empty array in args yourself. Use the generator for the populated and edge variants.
How do I render a long-name overflow story?
Generate a normal record, then override name with a deliberately long string in the story's args via object spread. The generator supplies realistic baseline content; you author the extremes that test wrapping and truncation.
Why does flipping Sequential IDs change the names and ages?
Because the id mode shifts the internal random stream: when ids are sequential, the UUID step no longer consumes random numbers, so every other field's value moves. Choose the id style before fixing the seed for a story so the content is stable.
Can I get TypeScript types for the story data?
Yes — paste a generated record into json-to-typescript to get an interface, which is handy for typing the story's args. For schema-based validation in CI, json-schema-generator produces a JSON Schema.
Is the output minified or pretty?
Always pretty-printed with 2-space indentation; there is no formatting control in the UI. Inside a story file that is fine — Prettier will reformat it. For minified data, run the output through json-minifier.
Are the emails safe if a story renders a mailto link?
Yes. Every email uses a non-routable test domain (example.com, test.org, demo.net, sample.io, mock.dev), so a reviewer clicking a generated mailto: link cannot send mail to a real person. Names repeat at large counts, so do not rely on email uniqueness.
Is my component data uploaded anywhere?
No. Generation runs entirely in your browser. There is nothing to upload — the tool ignores input and the generated story data never leaves your machine. Only an anonymous usage counter is recorded for signed-in dashboard stats.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.