Common patterns
Shared API across all exercises
All built-in exercises share this API. Type-specific props (entries, grids, variants) are documented on each catalogue page.
Layout
Every exercise wraps ExerciseLayout. Pass these to override the default header from the book language:
| Prop | Type | Description |
|---|---|---|
title | ReactNode | Heading shown next to the type icon |
description | ReactNode | Supporting text under the title. Omit for the language default; pass null or false to hide it |
info | ReactNode | Hint shown in an info popover |
icon | LucideIcon | ReactNode | Replaces the default type icon |
<YesNo
title="True or false"
description="Answer every statement."
info="Use what you read on this page."
entries={[
{ text: "The sky is blue.", answer: true },
]}
/>
<YesNo description={null} entries={entries} />Inline formatting
Display strings (titles, descriptions, info, labels, entry text, clues) accept CommonMark emphasis. Markers are parsed at render time into <em> and <strong>; they are not HTML.
| Marker | Result |
|---|---|
*italic* or _italic_ | italic |
**bold** or __bold__ | bold |
***both*** | bold italic |
Interior underscores stay literal (snake_case). Unmatched markers and HTML tags (<b>) show as text. For anything richer (images, links, custom markup), pass a ReactNode instead.
- The mitochondria is the powerhouse of the cell.
- Water boils at 100°C at sea_level.
<YesNo
title="True or **false**"
description="Decide if each statement is *accurate*."
entries={[
{ text: "The **mitochondria** is the *powerhouse* of the cell.", answer: true },
{ text: "Water boils at 100°C at sea_level.", answer: true },
]}
/>Do not put emphasis markers in answers, crossword or word-search solutions, grid letters, or MarkWords paragraphs ([word] tokens). Inline blank values (typed answers, dropdown values, drag chips used for matching) are compared as plain strings.
Custom exercises can use the same helper:
import { formatInlineText } from '@bside-tech/tbx-ui';
<span>{formatInlineText(label)}</span>Labels
Optional overrides for button text, results display, and validator metadata. Supported keys vary by component:
- YesNo:
true,false(Yes/No buttons),check,reset,results - Crosswords:
across,downfor direction labels - GroupItems: Group ids from entries for zone headings;
itemsfor the common pool - InlineDragAndDrop:
itemsfor the choice-bank heading - Others:
check,reset,results(e.g. "correct" in "X / Y correct")
checkOn
"manual"(default) — Shows Check/Reset buttons. User validates when ready."auto"— Validates as soon as answers are provided. No Check button.
Check callbacks
Run arbitrary code when a check succeeds or fails — play a sound, show a notification, log analytics, and so on.
import { toast } from '@heroui/react';
<YesNo
entries={entries}
onSuccess={() => toast('Well done', { variant: 'success' })}
onFailure={() => toast('Try again', { variant: 'danger' })}
/>| Prop | Type | Description |
|---|---|---|
onSuccess | () => void | Called when the exercise is checked and all answers are correct |
onFailure | () => void | Called when the exercise is checked and at least one answer is wrong |
Callbacks fire once per check(), after the overall result is computed. They do not fire on reset, or while the student is still editing (isCorrect is null).
They apply to both checkOn: "manual" and "auto". With "auto", onFailure can run on every answer change — prefer onSuccess, or debounce, if that would be noisy.
FindWords has no Check button. onSuccess runs when the last word is found. onFailure runs when a committed selection matches no remaining word (re-selecting an already found word does nothing).
The same options exist on the exercise hooks (usePickMultiExercise, useFillBlanksExercise, and the others), so custom exercises get the same behaviour.
For page-wide defaults and worked examples (sound, notification, analytics), see Exercise feedback.
ExerciseFeedback
Wrap exercises in <ExerciseFeedback> to set default callbacks once. Per-exercise onSuccess / onFailure override the defaults.
import { ExerciseFeedback, YesNo, PickOne } from '@bside-tech/tbx-ui/components';
<ExerciseFeedback
onSuccess={playSuccess}
onFailure={playFail}
>
<YesNo entries={yesNoEntries} />
<PickOne entries={pickOneEntries} />
</ExerciseFeedback>classNames
Object to customize CSS classes for styling individual parts. Each component documents its supported keys (e.g. root, list, item, buttons, checkButton, resetButton, result).
ExerciseGroup integration
All exercises integrate with ExerciseGroup and ExerciseResults for grouped scoring. Wrap multiple exercises in <ExerciseGroup> to get aggregated correct / total counts.