Build an Enneagram test in React + TypeScript
By Bernard Huang · Updated
Start with a complete local app instead of rebuilding the scoring rules. This starter wraps AgentTune’s existing Enneagram scorer in a typed React interface and includes the frozen questions, source code and dependency lockfile.
Download and run the complete app
Download the React + TypeScript starter ZIP. Extract it into a local development folder. Use a supported Node.js release satisfying 22.12 or newer, then run:
cd enneagram-react-typescript
npm ci
npm run devOpen the local address printed by Vite. For a production build, run npm run build, then npm run preview to inspect it. Publish the generated dist/ folder with a static host. Serve the app over HTTP rather than opening its index file directly.
The archive includes pinned React, TypeScript and Vite dependencies plus a lockfile. There is no backend, authentication or answer submission. Installation fetches development packages; using the questionnaire does not send answers to AgentTune.
One scorer, with a TypeScript boundary
The app loads the unchanged canonical public/score.js file before its React entry. The TypeScript wrapper describes the result and calls that scorer; it does not maintain a second copy of the scoring algorithm.
interface Score {
version: string;
scores: Record<string, number>;
topScore: number;
leaders: number[];
tied: boolean;
dominantType: number | null;
}The scorer requires exactly 36 integer responses from 1 to 5, in the supplied item order. It rejects missing values, sparse arrays, strings and out-of-range numbers. TypeScript helps the UI use the contract, while the runtime checks protect the actual scoring call.
Preserve uncertainty in the result
Each type has four questions and a raw score from 4 to 20. A result of 16/20 is a raw questionnaire total, not an 80th percentile or an 80% probability of being that type. The questions are not reverse-scored.
When two or more types share the maximum, the app lists every leader and leaves dominantType null. Answering Neutral to all 36 items gives all nine types 12 points. The result screen explicitly calls that a tie and displays all nine totals. It does not choose the first key or infer a wing.
This choice matters in the AI archive: Opus has 65 tied Enneagram administrations out of 100, and Fable has 44. A single winner would conceal information in many of those records. The starter is also a self-reflection aid, not a diagnosis or a validated personality measure for an AI.
Make the questionnaire usable with a keyboard
Each statement is the legend of a native fieldset. Each response has a visible label and a radio button, so keyboard users can move through groups and change options with standard controls. The app shows six questions per page and preserves answers when moving back.
Submitting an incomplete page identifies the first missing question and moves focus to its first radio. Moving to another page or the result focuses the new section heading. Error messages use an alert region; result tables use row and column headers. These behaviors are included in the source and should be retained when restyling.
The app intentionally keeps answers only in component state. Reloading starts over. If you add persistent profiles or a server, explain the changed data handling and design the storage separately.
Know which files to change
src/App.tsxcontrols pagination, selection, validation and results.src/styles.csscontrols layout, contrast and focus indicators.src/questions.jsoncontains the frozen items, type keys and provenance.src/scorer.tsdescribes and calls the canonical scorer.public/score.jscontains the scoring implementation.
If you reorder questions, update the scorer’s mapping as well. Its current contract groups four consecutive items per type. Changing wording or item count creates a different instrument and should receive a new version, rather than silently retaining the existing score label.
Questionnaire provenance and reuse
The code is MIT licensed. That license does not relicense third-party question text. The included metadata points to the Open-Source Enneagram of Personality Scales development material. Its current live test has 54 items; this frozen AgentTune implementation has 36, so their keys and totals are not interchangeable. Review upstream rights for your intended use.
Before publishing an adaptation, test a blank page, keyboard navigation, back navigation, an all-neutral result, a unique winner and resetting the form. Keep ties visible. For the standalone JavaScript scorer and its complete item contract, see the Enneagram developer resource.