Skip to content

Author content

The Studio editor keeps the activity in 3 separate fields: HTML, CSS, and JavaScript. The LMS places the HTML inside the component, adds the CSS to the page, then executes the JavaScript.

Call the global submitInteraction(data) function with a JSON-serializable object. The complete object is saved as the learner’s latest response.

submitInteraction({
answer: "Paris",
correct: true,
feedback: "Paris has been France's capital since 987.",
timeSpent: 12
});

The XBlock interprets these conventional properties:

PropertyTypePurpose
answerstring-compatibleCompared with a configured single answer when JavaScript does not supply correct.
correctbooleanAwards the full weight when true and zero when false.
feedbackstringOverrides the configured correct or incorrect feedback for this response.
timeSpentnumberStored with the response and displayed with previous feedback. The XBlock does not calculate it.

You can include additional JSON-compatible properties for state or analytics. Every call replaces the saved latest response and increments the learner’s interaction count.

submitInteraction() sends its request asynchronously and does not return a promise or response value to author code. Render immediate custom UI in your own JavaScript; the XBlock displays its configured grading feedback after the server responds.

When Completion Mode is Manual, call:

window.markComplete();

This records completion once without saving a response or publishing a grade. It can also complete an On view block early. The server rejects the call in On submit mode.

  • Write plain browser JavaScript. Do not use import or export.
  • Use top-level function declarations for functions referenced by inline HTML attributes such as onclick.
  • Prefix CSS classes and element IDs for your activity to avoid collisions with Open edX and other course components.
  • Keep the activity compact. It renders inline within a course unit, not as a standalone page.
  • Use unique global function names. Author JavaScript shares the page’s global scope.
  • Prefer built-in browser APIs and self-contained assets. External resources add privacy, availability, and content-security-policy dependencies.
  • Use native buttons, inputs, labels, fieldsets, and headings.
  • Make every action usable with a keyboard.
  • Keep visible focus states and sufficient color contrast.
  • Use aria-live or role="status" for dynamic custom results when appropriate.
  • Do not communicate correctness through color alone.
  • Test the published activity at narrow widths and browser zoom up to 200%.
<div class="capital-check">
<p id="capital-check-question">What is the capital of France?</p>
<div aria-labelledby="capital-check-question">
<button type="button" onclick="capitalCheckSubmit('Paris')">Paris</button>
<button type="button" onclick="capitalCheckSubmit('London')">London</button>
</div>
<p id="capital-check-result" role="status"></p>
</div>
.capital-check {
padding: 16px;
border: 1px solid #d9d9d9;
border-radius: 9px;
}
.capital-check button {
margin: 8px 8px 0 0;
}
var capitalCheckStartedAt = Date.now();
function capitalCheckSubmit(answer) {
var correct = answer === "Paris";
document.getElementById("capital-check-result").textContent =
correct ? "Correct" : "Try again";
submitInteraction({
answer: answer,
correct: correct,
timeSpent: Math.round((Date.now() - capitalCheckStartedAt) / 1000)
});
}

For scoring behavior, continue to Grading and completion.