Make production transparent. Try MDCplus
Try it yourself Get guided demoHow Do You Create Manufacturing KPI Widgets with Cursor and v0.dev?
How Do You Generate Manufacturing KPI Widgets with Cursor and v0.dev?
Short answer: use v0.dev to generate the visual component in isolation, then use Cursor with full repo context to wire it into your existing dashboard — each tool doing the half it's actually good at. The mistake most people make is trying to do both jobs with one tool: v0.dev has no knowledge of your codebase, and Cursor is slower at iterating on pure visual design. Splitting the work along that seam is what makes the workflow fast. This article covers the split, prompts for common manufacturing KPIs, and the integration problems that show up at the handoff.
The two-tool workflow at a glance
v0.dev Cursor Composer
------ ---------------
Generate widget in isolation Wire it into the repo
No repo context needed Full repo context
Fast visual iteration --> Match existing conventions
Mock/static props Connect real data layer
Output: a component file Output: integrated feature
Contents:
- Why splitting the tools works
- Prompting v0.dev for KPI widgets
- Getting manufacturing KPIs right
- The handoff: from generated component to your repo
- Wiring it up with Cursor
- Keeping widgets visually consistent
- Common pitfalls
- Frequently asked questions
- Conclusion
Why splitting the tools works
v0.dev generates React components from a text description and renders them immediately, with a fast visual iteration loop — you see the result, refine the prompt, see it again. What it doesn't have is any knowledge of your existing codebase: your data fetching patterns, your component library, your naming conventions, or the six other widgets this one needs to sit beside.
Cursor works inside your actual repository with full context. It can match existing patterns, import from the right places, and wire a component into your data layer correctly — but iterating on pure visual design through it is slower than v0's immediate render loop.
Hence the split: design in isolation where iteration is fastest, integrate where context lives. This also produces a useful discipline — because the widget is generated standalone with props, it's forced to be a presentational component with no data fetching baked in, which is the right architecture anyway.
Prompting v0.dev for KPI widgets
Two things make a large difference in v0 output quality for manufacturing widgets: specifying the states beyond the happy path, and describing the data as props rather than letting it invent a data source.
Create a scrap rate KPI widget as a React component using Tailwind. It receives props:
current(percentage),target(percentage),trend(array of daily values),periodLabel(string), andstatus('ok' | 'warning' | 'critical' | 'no-data').Show the current value large, the target as a reference, a compact sparkline for the trend, and a clear visual indication when current is worse than target. Include all four status states — the 'no-data' state must look distinctly different from a zero value, not just show 0%.
Do not fetch data or use any hooks for data loading. Pure presentational component, props only. Do not invent additional props beyond the ones listed.
That last constraint matters more than it looks. Left unconstrained, v0 will happily add props your data layer doesn't provide — a comparison to last quarter, a target trend line — which then have to be either implemented or stripped out during integration.
Getting manufacturing KPIs right
Generated widgets frequently look correct while displaying a metric that's subtly wrong for manufacturing use. A few specifics worth building into prompts:
| KPI | What the widget must get right |
|---|---|
| Scrap rate | Lower is better — the "good" direction is inverted versus most business KPIs, and generated widgets routinely color it backwards |
| MTBF | Higher is better; meaningless over short periods with few failures — needs a minimum-sample caveat rather than a confident number |
| MTTR | Lower is better; heavily skewed by single long repairs, so a median alongside the mean is often more honest |
| Shift target attainment | Needs a partial-period state — showing 40% attainment two hours into a shift as "critical" is misleading |
| OEE | Should show the three component factors, not just the product; a single number hides which loss is driving it |
The partial-period problem is worth stating explicitly in prompts for any target-based widget: "If the period is still in progress, show progress against elapsed time rather than against the full-period target, and label it as in-progress." Without that, every shift-target widget looks alarming for the first six hours of every shift, and people learn to ignore it.
The handoff: from generated component to your repo
The handoff is where most of the friction lives, and it's predictable enough to plan for. Generated components typically arrive with:
- Their own utility functions for formatting numbers and dates, duplicating whatever your repo already has.
- Inline Tailwind classes with arbitrary values rather than your design tokens — hardcoded colors instead of your semantic status colors.
- A component library assumption that may not match yours, particularly if you use a different base than the generated code expects.
- No TypeScript types shared with your data layer — locally defined prop types that will drift from your actual API response shape.
None of these are hard to fix; all of them are easy to skip when the widget already looks right. Skipping them repeatedly is exactly how a dashboard codebase turns into the sprawl problem covered in our piece on managing AI-generated dashboard code.
Wiring it up with Cursor
Cursor's advantage is repo context, so the prompt should lean on it explicitly rather than describing what your conventions are:
I'm adding the ScrapRateWidget component in @ScrapRateWidget.tsx to this dashboard. Before writing code, look at @DowntimeWidget.tsx and @UtilizationWidget.tsx to see how existing widgets handle data fetching, loading states, and error states.
Refactor the new widget to match those patterns exactly: use our existing data hook, our shared formatting utilities, and our design tokens instead of the hardcoded Tailwind values it currently has. Reuse our existing status color constants rather than the literal colors in the generated file. Type the props against our actual API response type, not the locally declared interface.
Then add it to the dashboard grid in @Dashboard.tsx following the same layout pattern as the other widgets. List anything in the generated component that conflicts with our conventions and how you resolved it.
Pointing at two existing widgets as reference is the highest-leverage part of that prompt. "Match our conventions" is vague; "match these two files" is concrete and produces markedly more consistent results.
Keeping widgets visually consistent
The failure mode of fast widget generation is a dashboard where every widget was designed independently and it shows — six different card paddings, four shades of red for "bad," inconsistent number formatting. It doesn't look broken, it looks amateurish, and it makes the data feel less trustworthy.
Two practices prevent most of it. First, generate a shared widget shell early — a card wrapper handling title, period label, loading, error, and no-data states — then generate only the inner content per widget. Second, feed your design tokens into every v0 prompt rather than fixing colors afterward: "Use these exact color values for status: ok #..., warning #..., critical #..., no-data #... Do not use any other colors for status indication."
The same applies to number formatting, which is a surprisingly common source of visual inconsistency — decide once whether percentages show one decimal or none, and state it in every prompt.
Common pitfalls
- Inverted "good" direction on loss metrics. Scrap rate, MTTR, and downtime are all better when lower; generated widgets default to treating higher as better and color them accordingly.
- No no-data state. The single most common omission, and the one that causes the most confusion in production — a widget showing 0% scrap because no data arrived reads as excellent performance.
- Data fetching baked into the widget. Makes it untestable and unreusable; keep generated widgets presentational and pass data in.
- Accumulating one-off utility functions. Every generated widget bringing its own date formatter is how a codebase quietly grows five slightly different ones.
- Skipping the Cursor integration pass. Dropping the v0 output in as-is because it looks fine is the fastest path to an inconsistent, unmaintainable dashboard.
- Widgets that only work at one size. Specify the expected grid sizes in the prompt; otherwise a widget looks right in the v0 preview and breaks in a narrow column.
Frequently asked questions
Can I skip v0.dev and just use Cursor for everything?
You can, and for a widget closely resembling ones you already have, it's often faster — Cursor can copy an existing pattern directly. v0 earns its place when you want genuinely new visual design and want to iterate on appearance quickly before committing to anything.
Do these tools work with component libraries other than the defaults?
Generally yes, but you have to say so explicitly in the prompt. Left unspecified, generated output tends toward the most common defaults, which then need translating during integration — cheaper to state upfront.
How do I stop each generated widget from looking slightly different?
Generate a shared widget shell once and reuse it, and include your exact design token values in every generation prompt. Fixing visual inconsistency after the fact across a dozen widgets costs far more than constraining it upfront.
Should generated widgets include their own data fetching?
No. Keep them presentational with data passed as props, and handle fetching in a container or hook that matches your repo's existing pattern. This makes widgets testable, reusable across dashboards, and much easier to integrate.
Conclusion
The two-tool split works because it matches each tool to what it's actually good at: v0.dev for fast visual iteration without repo context, Cursor for integration with full repo context. The manufacturing-specific care goes into the KPI semantics — inverted loss metrics, partial periods, minimum sample sizes, and a no-data state distinct from zero — none of which a general-purpose generator produces by default. And the integration pass is not optional: skipping it is how a fast workflow turns into a dashboard nobody wants to maintain.
Related articles:
- How Do You Stop AI-Generated Dashboards from Sprawling?
- How Do You Prompt-Engineer a Custom OEE Dashboard for Your Machines?
- Production KPI Adoption Guide
- Vibe-Coding vs Low-Code: Which Is Better for Manufacturing Dashboards?
- MDCplus Machine Connectivity & Integrations
About MDCplus
Our key features are real-time machine monitoring for swift issue resolution, power consumption tracking to promote sustainability, computerized maintenance management to reduce downtime, and vibration diagnostics for predictive maintenance. MDCplus's solutions are tailored for diverse industries, including aerospace, automotive, precision machining, and heavy industry. By delivering actionable insights and fostering seamless integration, we empower manufacturers to boost Overall Equipment Effectiveness (OEE), reduce operational costs, and achieve sustainable growth along with future planning.
Ready to increase your OEE, get clearer vision of your shop floor, and predict sustainably?