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.
Submit an interaction
Section titled “Submit an interaction”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:
| Property | Type | Purpose |
|---|---|---|
answer | string-compatible | Compared with a configured single answer when JavaScript does not supply correct. |
correct | boolean | Awards the full weight when true and zero when false. |
feedback | string | Overrides the configured correct or incorrect feedback for this response. |
timeSpent | number | Stored 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.
Mark a manual activity complete
Section titled “Mark a manual activity complete”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.
Runtime constraints
Section titled “Runtime constraints”- Write plain browser JavaScript. Do not use
importorexport. - 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.
Accessibility checklist
Section titled “Accessibility checklist”- 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-liveorrole="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%.
A compact example
Section titled “A compact example”<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.