implement-multiple-choice-question

asmith7013's avatarfrom asmith7013

Create D3 questions with radio button selections and optional explanations. Students select from options and explain their reasoning.

0stars🔀1forks📁View on GitHub🕐Updated Jan 3, 2026

When & Why to Use This Skill

This Claude skill enables the seamless creation of interactive D3.js multiple-choice questions featuring radio buttons, clickable cards, and optional reasoning fields. It provides a standardized framework for developers and educators to build robust educational assessments with built-in state management, LaTeX support for equations, and mobile-friendly UI components.

Use Cases

  • Mathematical Assessments: Creating questions where students select the correct equation or relationship from a list of LaTeX-rendered options.
  • Conceptual Quizzes: Developing single-selection questions that require students to choose a statement and provide a written justification to discourage guessing.
  • Visual Identification: Building interactive grids where students identify the correct graph, diagram, or image among several visual choices.
  • Interactive Practice Sets: Implementing mobile-responsive practice questions with large touch targets and real-time state saving for student progress tracking.
nameImplement Multiple Choice Question
descriptionCreate D3 questions with radio button selections and optional explanations. Students select from options and explain their reasoning.

Implement Multiple Choice Question

Use this skill when creating questions where students:

  • Select one option from a list of choices
  • Choose between equations, statements, or concepts
  • Make a selection and explain their reasoning

When to Use This Pattern

Perfect for:

  • "Which equation represents the relationship?"
  • "Select the correct statement"
  • "Choose the graph that matches..."
  • Any single-selection question with explanations

Not suitable for:

Components Required

Copy these from .claude/skills/question-types/snippets/:

Required

  • cards/standard-card.jscreateStandardCard()

Optional

  • cards/explanation-card.jscreateExplanationCard() - For reasoning
  • cards/video-accordion.jscreateVideoAccordion() - For help videos

Quick Start

  1. Review the pattern guide: PATTERN.md (if exists)
  2. Study working examples:
    cat courses/IM-8th-Grade/modules/Unit-3/assignments/Ramp-Up-01/questions/04/attachments/chart.js
    cat courses/IM-8th-Grade/modules/Unit-3/assignments/Ramp-Up-01/questions/06/attachments/chart.js
    

Key Implementation Decisions

  1. Option display - Simple text, equations, or visual cards?
  2. Selection style - Radio buttons or clickable cards?
  3. State structure - Store selected option ID
  4. Explanation requirement - Required or optional?

State Shape

function createDefaultState() {
  return {
    selectedOption: null,  // ID of selected option
    explanation: ""
  };
}

Core Pattern (Clickable Cards)

const OPTIONS = [
  { id: "opt1", text: "y = 2x + 3", display: "\\(y = 2x + 3\\)" },
  { id: "opt2", text: "y = 3x + 2", display: "\\(y = 3x + 2\\)" },
  { id: "opt3", text: "y = x + 5", display: "\\(y = x + 5\\)" },
];

function renderOptions(container) {
  const optionsDiv = container.append("div")
    .style("display", "flex")
    .style("flex-direction", "column")
    .style("gap", "12px");

  OPTIONS.forEach(option => {
    const isSelected = chartState.selectedOption === option.id;

    const optionCard = optionsDiv.append("div")
      .style("padding", "16px")
      .style("border", isSelected ? "2px solid #3b82f6" : "1px solid #e5e7eb")
      .style("border-radius", "12px")
      .style("background", isSelected ? "#eff6ff" : "#ffffff")
      .style("cursor", interactivityLocked ? "default" : "pointer")
      .style("transition", "all 0.2s")
      .on("click", () => {
        if (interactivityLocked) return;
        chartState.selectedOption = option.id;
        renderOptions(container);  // Re-render to show selection
        sendChartState();
      });

    optionCard.append("div")
      .style("font-size", "18px")
      .html(option.display);
  });
}

Core Pattern (Radio Buttons)

function renderOptions(container) {
  const form = container.append("form");

  OPTIONS.forEach(option => {
    const label = form.append("label")
      .style("display", "block")
      .style("margin", "12px 0")
      .style("cursor", "pointer");

    label.append("input")
      .attr("type", "radio")
      .attr("name", "choice")
      .attr("value", option.id)
      .property("checked", chartState.selectedOption === option.id)
      .property("disabled", interactivityLocked)
      .on("change", function() {
        chartState.selectedOption = this.value;
        sendChartState();
      });

    label.append("span")
      .style("margin-left", "8px")
      .html(option.display);
  });
}

Working Examples

In codebase:

Common Variations

With Explanation Card

createExplanationCard(d3, container, {
  prompt: "Explain why you selected this option.",
  value: chartState.explanation,
  onChange: (value) => {
    chartState.explanation = value;
    sendChartState();
  },
  locked: interactivityLocked
});

Visual Options (Images/Graphs)

OPTIONS.forEach(option => {
  const optionCard = optionsDiv.append("div");
  
  // Render graph or image
  if (option.type === "graph") {
    renderGraph(optionCard, option.data);
  } else if (option.type === "image") {
    optionCard.append("img").attr("src", option.imageUrl);
  }
});

Grid Layout

const optionsGrid = container.append("div")
  .style("display", "grid")
  .style("grid-template-columns", "repeat(2, 1fr)")
  .style("gap", "16px");

Implementation Checklist

  • Defined OPTIONS array with unique IDs
  • Created createDefaultState() with selectedOption field
  • Rendered option cards or radio buttons
  • Implemented click/change handlers to update state
  • Added visual feedback for selected option
  • Added explanation card (if needed)
  • Implemented setInteractivity() to disable selection when locked
  • Implemented applyInitialState() to restore selection
  • Tested selection changes
  • Tested state restoration
  • Tested locking/unlocking

Tips

  1. Clear visual feedback - Make selected option obviously different
  2. Use MathJax/KaTeX - For mathematical expressions in options
  3. Provide context - Use intro cards to explain what students are selecting
  4. Test on mobile - Ensure touch targets are large enough (min 44x44px)
  5. Require explanation - Helps prevent guessing, encourages reasoning

Styling Tips

Hover effects:

.on("mouseover", function() {
  if (!interactivityLocked) {
    d3.select(this).style("background", "#f9fafb");
  }
})
.on("mouseout", function() {
  const isSelected = /* check selection */;
  d3.select(this).style("background", isSelected ? "#eff6ff" : "#ffffff");
})

Focus states for accessibility:

optionCard
  .attr("tabindex", "0")
  .on("keypress", (event) => {
    if (event.key === "Enter" && !interactivityLocked) {
      chartState.selectedOption = option.id;
      renderOptions(container);
      sendChartState();
    }
  });

Related Skills

Additional Resources