Skip to content
Back to skills

Collection

ASecurity

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

  • 24 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 8, 2026
developmentjavascriptjavabashexpress

Works with

  • cursor
  • cli

Security analysis

A100/100

Pro scans all 21 files and shows the line behind each finding

Scanned September 8, 2026

npx -y skills add mattnigh/skills_collection --skill collection --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Collection?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Collection
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mattnigh-collection-81f6f7c1/badge)](https://www.skillsdirectory.com/skills/mattnigh-collection-81f6f7c1)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: Implement Multiple Choice Question
description: Create 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:**
- Multiple selections (checkboxes) → use standard checkbox pattern
- Drag-and-drop matching → use [implement-drag-match-question](../implement-drag-match-question/SKILL.md)
- Value entry → use [implement-table-question](../implement-table-question/SKILL.md)

## Components Required

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

### Required
- `cards/standard-card.js` → `createStandardCard()`

### Optional  
- `cards/explanation-card.js` → `createExplanationCard()` - For reasoning
- `cards/video-accordion.js` → `createVideoAccordion()` - For help videos

## Quick Start

1. **Review the pattern guide**: [PATTERN.md](PATTERN.md) (if exists)
2. **Study working examples**:
   ```bash
   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

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

## Core Pattern (Clickable Cards)

```javascript
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)

```javascript
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:**
- [IM-8th-Grade Ramp-Up-01 Q04](../../../../../courses/IM-8th-Grade/modules/Unit-3/assignments/Ramp-Up-01/questions/04/attachments/chart.js) - Equation selection
- [IM-8th-Grade Ramp-Up-01 Q06](../../../../../courses/IM-8th-Grade/modules/Unit-3/assignments/Ramp-Up-01/questions/06/attachments/chart.js) - Multiple choice with explanation

## Common Variations

### With Explanation Card
```javascript
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)
```javascript
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
```javascript
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:**
```javascript
.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:**
```javascript
optionCard
  .attr("tabindex", "0")
  .on("keypress", (event) => {
    if (event.key === "Enter" && !interactivityLocked) {
      chartState.selectedOption = option.id;
      renderOptions(container);
      sendChartState();
    }
  });
```

## Related Skills

- [implement-text-response-question](../implement-text-response-question/SKILL.md) - For selection + explanation focus
- [implement-drag-match-question](../implement-drag-match-question/SKILL.md) - For matching multiple items
- [create-d3-question](../../create-d3-question/SKILL.md) - Parent workflow skill

## Additional Resources

- [snippets/form-inputs.js](../snippets/form-inputs.js) - Form input patterns
- [snippets/cards/standard-card.js](../snippets/cards/standard-card.js) - Card styling

Files in this skill

  • 0Chan-smc__claude-code-workflow-lab__claude__skills__frontend-dev-guidelines__SKILL.md15.1 KB
  • 17hz__nextjs-template__claude__skills__example-skill__SKILL.md316 B
  • 1ambda__dataops-platform__claude__skills__context-synthesis__SKILL.md3.5 KB
  • 1natsu172__dotfiles__claude__skills__git-analysis__SKILL.md5.4 KB
  • 1natsu172__dotfiles__claude__skills__github-pr-best-practices__SKILL.md7.7 KB
  • 23Maestro__prospect-pipeline__claude__skills__npid-fastapi-skill.md26.1 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-code-javascript__SKILL.md15.7 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-code-python__SKILL.md17.5 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-expression-syntax__SKILL.md9.4 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-mcp-tools-expert__SKILL.md12.5 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-node-configuration__SKILL.md16.6 KB
  • 360AYA25__ClaudeN8N__claude__skills__n8n-workflow-patterns__SKILL.md11.2 KB
  • 3x-Projetos__claude-memory-framework__claude__skills__scientist__SKILL.md14.8 KB
  • 5MinFutures__futures-arena__claude__skills__migration-tracker__SKILL.md16.2 KB
  • 5MinFutures__futures-arena__claude__skills__planning-guidelines__SKILL.md11.8 KB
  • 92Bilal26__TaskPilotAI__claude__skills__assessment-builder__SKILL.md17.5 KB
  • 92Bilal26__TaskPilotAI__claude__skills__book-scaffolding__SKILL.md19.1 KB
  • 92Bilal26__TaskPilotAI__claude__skills__code-validation-sandbox__SKILL.md6.2 KB
  • 92Bilal26__TaskPilotAI__claude__skills__exercise-designer__SKILL.md18.1 KB
  • 92Bilal26__TaskPilotAI__claude__skills__learning-objectives__SKILL.md24.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…