Product demo for frontend developers: build it in your repo
Build a product demo for frontend developers inside your repo, keep it synced as you ship, and handle mock data, edge cases, sharing, and performance.

The real cost of a product demo for frontend developers isn't the first build. It's every update after you ship.
A repo-native demo fixes that. Mount it under a demo route in your existing frontend, share the same components and styles as production, and when the UI changes, the demo picks up the update instead of breaking quietly. No separate app. No re-recording. Just a folder and a route that move with the codebase.
Build the product demo in your repo, not beside it
Why a separate demo app turns into duplicate work
A separate demo app starts as a copy of your real frontend. The moment you rename a nav item, update a component API, or change a layout, the copy drifts. Now you have two frontends to maintain, one that ships and one that slowly stops matching the product. Most teams find out the hard way: a stakeholder opens the demo link the week after a big UI push and sees last sprint's interface.
Stripe's engineering team writes about tight coupling between their Dashboard codebase and user-facing products. The same problem shows up in demos. The more your demo diverges from the production source, the more work it takes to sync later.
What repo-native actually means in practice
A repo-native product demo is a route, or a small set of routes, inside your existing app. The directory might look like:
The demo folder imports the same components, uses the same design tokens, and runs through the same build pipeline. Mocked state replaces real API calls. The demo is not a separate product. It is your product, with controlled data.
Set up demo routes without splitting the app
The route boundary that keeps demo work isolated
Mount demo pages under `/demo` or a similar prefix and wrap them in their own layout component. The layout can strip navigation chrome, inject a demo banner, or set a context flag your components can read. Everything else, the actual UI components, the CSS, the responsive grid, stays shared.
Vercel's writing on the frontend developer experience describes route-based composition as the natural unit of frontend work. That fits here too. The demo route is just another route, not a parallel universe.
The shared-component pattern that avoids drift
The rule is simple: if a component exists in production, import it in the demo. Don't copy it. A copied `Button.tsx` in a demo folder will be wrong the next time someone updates the original. An imported `Button.tsx` stays current.
This applies to page shells, form components, modals, and navigation elements. The demo gets the same markup the product ships. When you update the production component, the demo updates with it.
What not to duplicate
Three traps make demo maintenance expensive:
- Copy-pasted markup. Inline HTML in a demo page that mirrors a production component means any change to the component needs a manual sync.
- Demo-only CSS forks. A separate stylesheet for the demo that overrides production styles means you're maintaining a style delta on top of a markup delta.
- Mock data scattered across files. Fixtures defined inline, in multiple files, with no clear home. When the data model changes, you end up hunting for every hardcoded value.
Put mock data in one file per demo route. Import it. When the shape changes, update one place.
Use HTML, CSS, and JavaScript to mirror the shipped UI
Match the production layout first, then the motion
Before you add transitions or hover animations, get the structure right. Grid, typography, spacing rhythm, and component hierarchy should match production closely. A stakeholder who opens the interactive product demo and sees a layout that feels slightly off will tune out the rest.
Start with a side-by-side comparison: open the real product next to the demo route and check grid alignment, font sizes, and spacing at both desktop and mobile widths. Add transitions and motion after the layout passes that check.
The CSS details that make a demo feel real
The small things break fidelity faster than the big things:
- Spacing rhythm. If production uses an 8px base unit, the demo needs the same. A 10px gap on a card reads as wrong even when the viewer can't name why.
- Hover states. Buttons, rows, and links that don't respond to hover make the demo feel like a screenshot. Import the production interaction styles, don't approximate them.
- Empty states. A list with zero items should render the same empty state the product shows. A blank white box is a fidelity hole.
- Responsive behavior. Check the demo at 375px. If a component reflows differently than production, the shared-component pattern broke somewhere.
Mock the hard states before the happy path looks done
The loading state that keeps the demo honest
A demo that jumps from blank to fully loaded in one frame reads as fake. Add skeleton screens or spinners with a short artificial delay, 400–800ms, so the demo shows the same transition the product shows. This matters most for tables, dashboards, and any view that normally waits on a network call.
Wire the delay into the mock data layer, not into the component. The component should behave exactly as it does in production. The demo data layer controls timing.
The edge case that proves the demo can handle reality
Pick one hard state and include it: an empty list, a failed form submission with validation errors, or a permission-restricted view. This does two things. It shows the product handles edge cases, which builds trust. And it forces you to verify the component actually renders those states correctly. Bugs that only show up in edge cases often stay hidden until a demo exposes them.
Realistic data without a backend detour
Frontend mock data should feel like real records, not `Test User` and `example@email.com`. Use plausible names, realistic timestamps, and amounts that match the product's actual scale. A SaaS dashboard showing `$1.00` in revenue looks like a toy. One showing `$48,230` in the right currency format looks like a product.
Seed this data in a single `fixtures/` directory. Keep it close to the demo routes, version it with the codebase, and update it whenever the data model changes. PostHog's take on product engineers describes this kind of end-to-end ownership: the person building the demo is also responsible for keeping the fixtures honest.
Keep the demo current as the frontend ships
The maintenance workflow after a UI change
When a production component changes, the demo update is usually a no-op. The shared-component pattern handles it. What needs attention:
- Check that the changed component still renders correctly in the demo context with mocked state.
- Update any fixture data that the change made stale, like new fields, renamed keys, or changed types.
- Verify the demo route still loads and the shareable link resolves.
That's the full checklist for most UI changes. It takes minutes when the demo is repo-native. It takes hours when the demo is a separate app or a recording.
The smallest sync loop that actually works
Tie demo verification to your existing merge workflow. Add a demo route check to your PR checklist, one item: "does the demo route still load and show realistic data?" If it does, ship. If it doesn't, the fix is usually one fixture update or one import path correction.
Don't let demo maintenance become its own backlog. Once it has a backlog, the demo is already stale.
Where AI coding tools help and where they do not
Cursor or Claude Code helps with two specific jobs: generating the initial mock data fixtures and making repetitive edits when a data model changes across multiple fixture files. Both jobs operate on real files in your repo.
What they do not help with is a demo that lives outside the repo, like a recording in Supademo's cloud or a separate app with its own deploy pipeline. An agent can't re-prompt a screenshot. It can update a TypeScript fixture file in thirty seconds. Keep the demo in the repo and the agent stays useful.
Make the demo work on a phone, in a browser, and in front of stakeholders
Responsive layouts that still read on a laptop screen share
The demo will be opened in a browser tab during a screen share at a resolution you didn't test. Check it at 1280px wide, the most common laptop viewport in a video call, and verify nothing overflows, truncates, or collapses in a way that looks broken. Set an explicit `max-width` on demo containers if the production layout assumes a wider viewport.
Performance, HTTPS, and CSP basics that keep it shippable
A shareable frontend demo needs three things to be safe to send:
- Fast first load. Lazy-load any heavy assets the demo doesn't need immediately. A demo that takes four seconds to paint loses the stakeholder before the first click.
- HTTPS. Any modern hosting provider gives you this. A plain HTTP link will trigger a browser warning that kills the impression before the demo loads.
- Sane content security policy. If your production CSP blocks inline scripts or external fonts, the demo inherits that policy. Test the demo link in an incognito tab before sending it.
The share link that preserves fidelity
Deploy the demo route to the same host as your production app, or to a preview URL from your CI pipeline. Don't screenshot it, don't record it, don't export it to a PDF. A live URL gives the stakeholder the real interaction model, clicks, hovers, transitions, not a flat approximation. When you send the link, it should open in a browser tab and behave exactly as it did when you last verified it.
Where Inkly comes in
The structural problem this article describes is that demos built outside the repo need a separate maintenance track. The fix is keeping the demo as code you own, in your repo, where any coding agent can touch it.
Inkly is built on that premise. The demo it produces is code, not a recording locked in a SaaS platform. When a UI change lands, you re-prompt your agent (Cursor, Claude, Codex) and the demo updates from the same source of truth as the product. No re-record, no re-capture, no second app to babysit. If you already have a coding agent set up, the path from rough interface to shareable demo your agent can maintain is a prompt, not a project. The tradeoff is simple: Inkly's MVP is bring-your-own-agent. The hosted in-app agent is on the roadmap, not shipped yet. If you're not already using Cursor or Claude Code, that setup step comes first.
FAQ
Q: How do I create a polished product demo from an existing frontend without building a separate app?
Add a `/demo` route to your existing app, wrap it in its own layout, and import the same components production uses. Replace real API calls with fixture data in a single `fixtures/` directory. The demo is now a folder in your repo, not a second frontend to maintain.
Q: How can I keep the demo current as the frontend ships new UI and state changes?
Shared components handle most updates automatically. When production changes, the demo inherits the change. What needs attention is fixture data: update any mock records that reference renamed fields or changed data shapes. Add a one-line demo check to your PR checklist and it stays current without becoming its own backlog.
Q: What should I do when the demo needs realistic data, loading states, and edge cases?
Add them early, not as polish. Wire a short artificial delay into your mock data layer to show loading states. Include at least one edge case, like an empty list, a validation error, or a restricted view. Seed fixture data with plausible names and realistic values. A demo that skips these states looks staged. One that handles them builds trust.
Q: How fast can an indie hacker or product engineer turn a rough interface into a convincing demo with AI coding tools?
It depends on how much of the frontend is already componentized and how clean the existing routes are. If components are shared and the app uses a route-based framework, adding a demo route with realistic fixture data is a few hours of work. An AI coding agent, like Cursor or Claude Code, speeds up fixture generation and repetitive data-model updates. It does not replace the structural decisions about what the demo should show.
Q: How do I make the demo clear enough for a PM or founder to explain the product in under a minute?
Pick three screens that tell the product's core story and link them in a linear flow. Remove any navigation that lets the viewer wander into unfinished corners. The demo doesn't need to cover every feature. It needs to answer one question clearly: what does this product do and why does it matter? Strip everything that doesn't serve that answer.
Conclusion
A repo-native demo moves when the frontend moves. No second app, no recording to re-capture, no maintenance backlog that grows every sprint. The architecture is simple: one demo route, shared components, fixture data in one place, and a one-line PR checklist item.
Pick one real route in your repo this week. Add a `/demo` prefix, swap the API calls for fixture data, and send the link to one stakeholder. That's the whole first step, and it's the last time you'll have to rebuild the demo from scratch.
Ship your next demo before the meeting starts
Interactive demos built from your real product and kept current as you ship, done for you.




