This guide does exactly that with a price calculator, then checks what it costs.
You need vagejs 0.11 or newer. Start a new site with npm create vagejs@latest my-site, or update with npm install vagejs@latest.
1. Install React and MDX
npm install react react-dom
npm install --save-dev @mdx-js/mdxReact draws the component. MDX lets you use it inside a page.
2. Write the component
Interactive components live in src/components/. Save this as src/components/PriceCalculator.tsx:
import { useState } from "react";
export default function PriceCalculator({ pricePerSeat }: { pricePerSeat: number }) {
const [seats, setSeats] = useState(5);
return (
<form className="calculator">
<label htmlFor="seats">How many people?</label>
<input id="seats" type="number" min={1} value={seats} onChange={(e) => setSeats(Number(e.target.value) || 1)} />
<p>
{seats} × ${pricePerSeat} = <strong>${seats * pricePerSeat} a month</strong>
</p>
</form>
);
}It's an ordinary React component. Nothing in it is specific to vagejs.
3. Use it in a page
A page that uses components is an MDX file: Markdown with components in it. Save this as src/pages/pricing.mdx:
---
title: Pricing
description: One simple price per person, with a calculator to see your total.
---
import PriceCalculator from "../components/PriceCalculator.tsx";
# Pricing
Every plan costs $12 per person a month. Work out your total:
<PriceCalculator client:visible pricePerSeat={12} />client:visible is what makes it interactive. Without it, the calculator would be plain HTML showing 5 people and $60, and typing in the box would do nothing.
You can choose when it starts:
| Directive | Starts |
|---|---|
client:load |
as soon as the page loads |
client:visible |
when it scrolls into view |
client:idle |
when the browser has nothing else to do |
client:visible suits anything below the fold: visitors who never scroll down never download it.
4. Try it
npm run devOpen /pricing/ and change the number. The total updates as you type. The calculator was already on the page before its JavaScript arrived, because vagejs turned it into HTML first.
5. Check the cost
Build the site and run the audit:
npm run build
npm run audit/pricing/ total 216.5 KB js 214.7 KB css 0.0 KB img 0.0 KB font 0.0 KB 3 req
warning budget /pricing/
javascript is 214.7 KB, over the 100 KB budget (performance.budgets.javascriptKb).Most of that is React. Every other page still shows js 0.0 KB. If the calculator is worth it, raise the budget in vage.config.ts:
performance: { budgets: { javascriptKb: 250 } },Run npm run audit again and the warning is gone. The budget is there so that adding JavaScript is a decision, not an accident.
What rules does an interactive component follow?
- The component must be exported from a file in
src/components/. - Props must be plain data: text, numbers, true or false, lists and objects. A function can't be sent to the browser.
- It can't have content between its tags, and it can't contain another interactive component.
- Interactive components work in MDX pages and React layouts. They're React only for now.
If you break a rule, npm run check names the component and says what to change.
Do you need React for this?
A lot of interactivity needs no JavaScript at all. A <details> element opens and closes. A link to #section jumps down the page. A form can send a message. Use a component when the page really has to respond to the visitor, like this calculator.
More on interactive components in vagejs
- React, Vue and MDX in the docs: layouts, MDX pages and every rule
- React, Vue and MDX: what the feature does and doesn't do