TBX Docs
ExercisesCatalogue

Crosswords

Fill-in crossword puzzles with clues and per-word validation

Crosswords renders an interactive crossword grid where users fill in answers. Each word is validated against a legend with clue and solution. Position, direction, and start coordinates are derived by matching solutions to words in the grid.

Import

import { Crosswords } from '@bside-tech/tbx-ui/components';

Example

Crossword
Fill in the crossword using the given clues.
12
3
4

Across

  • 1. A primary color
  • 3. Bits and bobs
  • 4. Conclusions

Down

  • 1. Toy on a string
  • 2. Have a rest
<Crosswords
  grid={[
    ["Y", "E", "L", "L", "O", "W", ""],
    ["O", " ", "I", " ", " ", " ", " "],
    ["Y", "", "E", "", "", "", ""],
    ["O", "D", "D", "S", "A", "N", "D"],
    ["", "", "O", "", "", "", ""],
    ["", "", "W", "", "", "", ""],
    ["", "E", "N", "D", "S", "", ""],
  ]}
  legend={[
    { clue: "A primary color", solution: "YELLOW" },
    { clue: "Toy on a string", solution: "YOYO" },
    { clue: "Have a rest", solution: "LIEDOWN" },
    { clue: "Bits and bobs", solution: "ODDSAND" },
    { clue: "Conclusions", solution: "ENDS" },
  ]}
/>

Grid format

The grid is a 2D array of strings. Each cell is either:

  • Letter — Fillable cell (user types the answer).
  • '' or ' ' — Blocked cell (black square in a crossword).

Legend format

Each legend entry has only clue and solution. Position, direction, and start coordinates are derived by matching each solution to words in the grid (in reading order: left-to-right, top-to-bottom).

FieldTypeDescription
cluestringThe clue text shown to the user
solutionstringThe correct answer (must match a word in the grid exactly)

Props

Prop

Type

Labels

Override labels via the labels prop. Supported keys: across, down (section headings), check, reset (buttons), results (e.g. "correct" in "3 / 5 correct"). No exercise label.

<Crosswords
  grid={grid}
  legend={legend}
  labels={{
    across: "Orizzontale",
    down: "Verticale",
    check: "Verifica",
    reset: "Ripristina",
    results: "corretti",
  }}
/>

Style

Tailwind v4 is available for customisations. Pass classes via the classNames prop, or override CSS variables for fine-grained control.

CSS Classes

KeyElement
rootRoot wrapper
gridGrid container
cellGrid cell (blocked or input)
legendLegend container
legendSectionAcross/Down section
legendItemClue list item
checkButtonCheck button
resetButtonReset button
resultResults text

CSS Variables

Scoped under .tbx-crosswords:

VariablePurpose
--crosswords-cell-sizeCell width and height (default 2rem; overridden by cellSize prop)
--crosswords-cell-bgFillable cell background (default)
--crosswords-cell-borderCell border
--crosswords-cell-filled-bgCell background when filled (before validation). Uses color-mix with --exercise-accent-color.
--crosswords-cell-filled-borderCell border when filled (before validation). Uses --exercise-accent-color.
--crosswords-cell-numberClue number color (top-left of word-start cells)
--crosswords-cell-textCell text color
--crosswords-cell-correctCell background when correct
--crosswords-cell-wrongCell background when wrong
--crosswords-legend-bgLegend background
--exercise-action-bg, --exercise-action-borderCheck/Reset buttons
--exercise-result-neutral, --exercise-result-correct, --exercise-result-wrongResults text

Hook

Use useCompareGrid when building custom crossword interfaces:

import { useCompareGrid } from "@bside-tech/tbx-ui/hooks";
import type { CrosswordsLegendEntryInput } from "@bside-tech/tbx-ui/hooks";

const { grid, setCell, wordResults, isCorrect, check, reset, resolvedLegend, getLegendId } =
  useCompareGrid({
    solutionGrid: grid,
    legend: legend, // CrosswordsLegendEntryInput[]
    checkOn: "manual",
  });
ReturnDescription
gridCurrent user grid (mutable copy)
setCellUpdate a single cell: setCell(row, col, value)
wordResultsPer-word correctness after check: { [id]: boolean } where id is {position}-{direction}
isCorrectnull = not validated, true/false = overall result
checkValidate current grid against legend solutions
resetClear user input and reset validation state
resolvedLegendFull entries with position, direction, startRow, startCol derived from the grid
getLegendIdGet id for an entry: getLegendId(entry)"1-horizontal"

On this page