@monarkmarkets/question-types
v1.0.9
Published
Question type components for Monark Markets
Readme
@monarkmarkets/question-types
A package of reusable React components for building interactive question interfaces including single choice, multiple choice, and scale-based questions.
Installation
npm install @monarkmarkets/question-typesPeer dependencies: Install
reactandreact-dom^18.2.0 || ^19.0.0in the consuming app. Styling helpers use Emotion and MUI (@emotion/react,@emotion/styled,@mui/material), which ship as direct dependencies of this package.
Features
- Multiple question formats - Single choice, multiple choice, and scale/slider questions
- Highly customizable - Extensive props for tailoring appearance and behavior
- Type-safe - Written in TypeScript with comprehensive type definitions
Components
SingleChoiceQuestion
A radio button-based question component that allows users to select exactly one option.
import {SingleChoiceQuestion} from '@monarkmarkets/question-types';
function MyForm() {
return (
<SingleChoiceQuestion
options={["Option 1", "Option 2", "Option 3"]}
explanation="Please select one option"
selectedOption="Option 1"
onSelect={(selected) => {
// Handle selection
}}
/>
);
}MultiChoiceQuestion
A checkbox-based question component that allows users to select multiple options.
import {MultiChoiceQuestion} from '@monarkmarkets/question-types';
function MyForm() {
return (
<MultiChoiceQuestion
options={["Option 1", "Option 2", "Option 3"]}
explanation="Please select all that apply"
selectedOptions={["Option 1"]}
onSelect={(selected) => {
// Handle selection
}}
/>
);
}ScaleQuestion
A slider-based question component for numeric or scale-based inputs.
import {ScaleQuestion} from '@monarkmarkets/question-types';
function MyForm() {
return (
<ScaleQuestion
options={["How much would you like to invest?"]}
explanation="Drag the slider to select an amount"
min={0}
max={1000000}
step={5000}
selectedValues={["50000"]}
defaultValue={0}
minLabel="Minimum Investment"
maxLabel="Maximum Investment"
currency={{
symbol: 'USD',
position: 'prefix',
locale: 'en-US'
}}
onSelect={(selected) => {
// Handle selection
}}
showNumberLabels={true}
/>
);
}Props
Common Props (BaseQuestionProps)
| Prop | Type | Default | Description | |----------------|------------------------------|------------|--------------------------------------------| | id | string | undefined | Optional unique identifier | | disabled | boolean | false | Whether the component is disabled | | error | string | undefined | Custom error message | | options | string[] | (required) | Array of options to display | | onSelect | (selected: string[]) => void | (required) | Callback function when selection changes | | explanation | string | undefined | Optional explanation or help text | | showNoneOption | boolean | false | Whether to show "None of the Above" option |
SingleChoiceQuestion Props
| Prop | Type | Default | Description | |----------------|----------------------------------------------------------|-----------|------------------------------------| | selectedOption | string | undefined | The currently selected option | | allowDeselect | boolean | false | Whether options can be deselected | | renderOption | (option: string, isSelected: boolean) => React.ReactNode | undefined | Custom render function for options |
MultiChoiceQuestion Props
| Prop | Type | Default | Description | |-----------------|----------------------------------------------------------|-----------|------------------------------------| | selectedOptions | string[] | [] | The currently selected options | | allowDeselect | boolean | true | Whether options can be deselected | | renderOption | (option: string, isSelected: boolean) => React.ReactNode | undefined | Custom render function for options |
ScaleQuestion Props
| Prop | Type | Default | Description | |------------------|---------------------------|------------|---------------------------------------------| | min | number | (required) | Minimum value of the scale | | max | number | (required) | Maximum value of the scale | | step | number | (required) | Step value for the scale | | defaultValue | number | 0 | Default value for the scale | | minLabel | string | undefined | Label for the minimum value | | maxLabel | string | undefined | Label for the maximum value | | marks | ScaleMark[] | undefined | Custom scale mark points | | showNumberLabels | boolean | false | Whether to show number labels on the scale | | currency | CurrencyConfig | undefined | Configuration for currency formatting | | formatDisplay | (value: number) => string | undefined | Custom function to format the display value | | selectedValues | string[] | [] | Previously selected values |
CurrencyConfig
| Property | Type | Description | |----------|----------------------|---------------------------------------| | symbol | string | Currency symbol (e.g., 'USD', 'EUR') | | position | 'prefix' | 'suffix' | Position of the currency symbol | | locale | string | Optional locale for number formatting |
ScaleMark
| Property | Type | Description | |----------|--------|----------------------------------------| | value | number | The value where the mark should appear | | label | string | The label to display at the mark |
Example
Here's an example of how to use the question components with data from the API:
import React, {useState} from 'react';
import {
SingleChoiceQuestion,
MultiChoiceQuestion,
ScaleQuestion
} from '@monarkmarkets/question-types';
import {QuestionnaireQuestionFormat} from '@monarkmarkets/api-client';
const QuestionRenderer = ({question, onAnswer}) => {
// Render the appropriate question component based on question format
switch (question.format) {
case QuestionnaireQuestionFormat.Scale:
return (
<ScaleQuestion
options={question.options}
explanation={question.explanation}
min={question.scaleMin || 0}
max={question.scaleMax || 1000000}
step={question.scaleStep || 5000}
selectedValues={[]}
defaultValue={0}
minLabel="Minimum Investment"
maxLabel="Maximum Investment"
currency={{
symbol: 'USD',
position: 'prefix',
locale: 'en-US'
}}
onSelect={onAnswer}
showNumberLabels={true}
/>
);
case QuestionnaireQuestionFormat.MultipleChoiceMultiple:
return (
<MultiChoiceQuestion
options={question.options}
explanation={question.explanation}
selectedOptions={[]}
onSelect={onAnswer}
/>
);
case QuestionnaireQuestionFormat.MultipleChoiceSingle:
return (
<SingleChoiceQuestion
options={question.options}
explanation={question.explanation}
selectedOption={undefined}
onSelect={onAnswer}
/>
);
default:
return <div>Unsupported question format</div>;
}
};
// Example usage in a parent component
const QuestionnaireForm = () => {
const [answers, setAnswers] = useState({});
const handleAnswer = (questionId) => (selected) => {
setAnswers(prev => ({
...prev,
[questionId]: selected
}));
};
// Sample question data (normally from API)
const sampleQuestions = [
{
id: "q1",
format: QuestionnaireQuestionFormat.MultipleChoiceSingle,
text: "What is your investment experience?",
explanation: "Please select your experience level",
options: [
"No prior investment experience",
"Some experience with public markets",
"Experienced with private investments",
"Professional investor"
]
},
{
id: "q2",
format: QuestionnaireQuestionFormat.Scale,
text: "How much would you like to invest?",
explanation: "Drag the slider to select an amount",
options: ["Investment Amount"],
scaleMin: 10000,
scaleMax: 1000000,
scaleStep: 10000
}
];
return (
<div className="questionnaire-form">
<h1>Investment Questionnaire</h1>
{sampleQuestions.map(question => (
<div key={question.id} className="question-container">
<h3>{question.text}</h3>
<QuestionRenderer
question={question}
onAnswer={handleAnswer(question.id)}
/>
</div>
))}
<button
onClick={() => console.log('Submitted answers:', answers)}
className="submit-button"
>
Submit
</button>
</div>
);
};Development & Verification
npm installnpm run build— generatesdist/index.js,dist/index.esm.js, and type declarations via Rollup.npx tsc --noEmit— fast regression check that catches type issues without touchingdist/.
Dependencies
react/react-dom^18.2.0 || ^19.0.0(peer deps)@emotion/react11.14.x@emotion/styled11.14.x@mui/material7.3.xlodash4.17.21
License
Copyright © 2025 Monark Markets. All rights reserved.
