Skip to content

[QuizQuestion] Allow each answer to have extra actions #660

@huyenltnguyen

Description

@huyenltnguyen

Description

This change is related to freeCodeCamp/freeCodeCamp#61906.

The MCQ component in /learn is currently a custom one. We do plan to migrate it to QuizQuestion, but the component is not compatible now that we are adding the speaking feature.

The challenge with adding extra actions / buttons to the answers is that each button must line up visually with its corresponding answer, without being mixed into the radio group itself.

We can't use the following pattern, even though it's the simplest way to achieve the alignment:

<fieldset>
  <legend>Question text</legend>

  <label for="option-1">Option 1</label>
  <input type="radio" id="option-1" />
  <button>Practice speaking option 1</button>

  <label for="option-2">Option 2</label>
  <input type="radio" id="option-2" />
  <button>Practice speaking option 2</button>

  <label for="option-3">Option 3</label>
  <input type="radio" id="option-3" />
  <button>Practice speaking option 3</button>
</fieldset>

The preferred structure is:

<fieldset>
  <legend>Question text</legend>

  <label for="option-1">Option 1</label>
  <input type="radio" id="option-1" />

  <label for="option-2">Option 2</label>
  <input type="radio" id="option-2" />

  <label for="option-3">Option 3</label>
  <input type="radio" id="option-3" />
</fieldset>

<div>
  <button>Practice speaking option 1</button>
  <button>Practice speaking option 2</button>
  <button>Practice speaking option 3</button>
</div>

This keeps the radios semantically correct, and separate the extra buttons from the radio group.

The drawback is that alignment becomes more involved. We need JS to calculate the position of the action buttons: the button group can sit on the same row as the fieldset, but each button must be offset to match its corresponding answer, and this requires measuring the legend height as well as the heights of the option elements above each button to keep the offsets in sync.


For /learn, the temporary structure I went with is:

<fieldset>
  <legend>Question text</legend>

  <div>
    <label for="option-1">Option 1</label>
    <input type="radio" id="option-1" />

    <label for="option-2">Option 2</label>
    <input type="radio" id="option-2" />

    <label for="option-3">Option 3</label>
    <input type="radio" id="option-3" />
  </div>
  
  <div>
    <button>Practice speaking option 1</button>
    <button>Practice speaking option 2</button>
    <button>Practice speaking option 3</button>
  </div>
</fieldset>

Which I know is not ideal, but it at least keeps the radios properly grouped. Having the button group as a sibling of the radio group allows us to handle the alignment through CSS grid.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions