Quickstart: Build Your First XBlock Aside#

Tags: developer quickstart

Build, install, and run a minimal XBlock Aside in a Tutor development environment. By the end of this quickstart, you will have an Aside that adds a small banner to every Problem block in a course, and you will understand the four moving parts every Aside has: the class, the decorated views, the entry point, and the install step.

This quickstart deliberately keeps the Aside trivial. For a more realistic recipe, work through Add an XBlock Aside next. For the conceptual background, see About XBlock Asides.

Prerequisites#

You need:

  • A running Tutor development environment with the LMS and Studio services accessible. Tutor’s Getting started guide walks through the install if you do not have one yet.

  • The installed Python version used by the target Open edX release.

  • A course in your devstack with at least one Problem block. The Tutor demo course works.

  • A text editor and a terminal.

You do not need:

  • Prior experience writing XBlocks. The Aside in this quickstart uses plain Python and a hardcoded HTML string.

  • Familiarity with the Open Learning XML (OLX) format.

Step 1: Create a Python package#

In a working directory of your choice, create the following file structure:

hello_aside/
├── pyproject.toml
└── hello_aside/
    ├── __init__.py
    └── Aside.py

Make __init__.py an empty file. The remaining steps describe what to put in the other two files.

Step 2: Write the Aside class#

In hello_aside/Aside.py, paste the following code:

from web_fragments.fragment import Fragment
from xblock.core import XBlockAside


class HelloAside(XBlockAside):
    """A trivial Aside that prints a banner above every Problem block."""

    @XBlockAside.aside_for("student_view")
    def student_view_aside(self, block, context=None):
        return Fragment(
            '<div style="padding:8px;background:#eef;border:1px solid #99c;">'
            'Hello from an XBlock Aside!'
            '</div>'
        )

    @classmethod
    def should_apply_to_block(cls, block):
        return getattr(block, "category", None) == "problem"

This is the entire implementation. Three things to notice:

  • The class subclasses XBlockAside.

  • The aside_for() decorator marks student_view_aside as the method to call when an XBlock’s student_view is being rendered.

  • should_apply_to_block() restricts the Aside to Problem blocks. Without it, the banner would appear on every block in every course.

Step 3: Configure the package#

In hello_aside/pyproject.toml, paste:

[project]
name = "hello-Aside"
version = "0.1.0"
requires-python = ">=X.Y"  # set to the minimum Python version for the target Open edX release
dependencies = ["XBlock", "web-fragments"]

[project.entry-points."xblock_asides.v1"]
hello_aside = "hello_aside.Aside:HelloAside"

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

The critical line is the one under [project.entry-points."xblock_asides.v1"]. It tells the Open edX platform that a class called HelloAside, in the hello_aside.Aside module, should be loaded as an Aside under the type name hello_aside. This entry point group is how every Aside is discovered.

Step 4: Install the package into Tutor#

From the directory containing hello_aside/, mount the package into Tutor and relaunch the development environment:

tutor mounts add lms,cms:./hello_aside:/openedx/hello_aside
tutor dev exec lms bash
pip install -e /openedx/hello_aside
exit
tutor dev restart lms

The mounts add command tells Tutor to mount the local package into both the LMS and Studio containers each time they start.

If you are not using Tutor, install the package directly into the LMS and Studio Python environments with pip install -e ./hello_aside, then restart both services.

Step 5: Enable the Aside system in the LMS#

The LMS gates Aside rendering on a global Django configuration model, XBlockAsidesConfig. Until that model is enabled, no Aside renders on any block, regardless of whether it is registered or installed.

Open the LMS Django admin in your browser:

http://<your-lms-host>/admin/lms_xblock/xblockasidesconfig/

Click Add to create a new revision. Check Enabled and click Save. The new revision becomes the current configuration immediately.

The same form has a Disabled blocks field that holds a space-separated list of block types on which asides will never render. The default value is about course_info static_tab. The hello_aside example targets problem blocks, which are not in the default disabled list, so no further changes are needed.

Studio has its own, separate gate — a different model, StudioConfig, controls whether asides render in Studio, and it defaults to disabled too. This quickstart’s hello_aside only decorates student_view, so it has nothing to show in Studio either way; see Add an XBlock Aside for the Studio half of enabling asides, and for adding an author-facing view in the first place.

Step 6: Verify the Aside is rendering#

Open a course in the LMS, navigate to a unit that contains a Problem block, and confirm a light blue banner reading “Hello from an XBlock Aside!” appears below the problem. If you see the banner, your Aside is working.

If the banner does not appear, work through these checks in order:

  1. The Aside is registered. Open a Django shell and run:

    from xblock.core import XBlockAside
    print(list(XBlockAside.load_classes()))
    

    The list should include hello_aside. If it does not, the entry point is not installed; recheck Step 3 and Step 4.

  2. The block type matches. Your test block must have category == "problem". A Video block, an HTML block, or a Discussion block will not trigger the Aside.

  3. The Aside failed to load, not just to apply. If your Aside’s type name doesn’t even show up in step 1’s load_classes() list, check the logs for a warning about failing to load it as a plugin — a broken import in your package is dropped silently at that stage, which is what actually makes a broken Aside look like a missing one. An exception raised after loading, inside student_view_aside or should_apply_to_block, is a different situation and isn’t swallowed the same way — it renders as a visible error block in place of the banner, rather than no banner at all; see Add an XBlock Aside for how to tell the two apart.

What You Just Built#

You have a working Aside with all four required pieces:

A class

HelloAside subclasses XBlockAside.

A decorated view

student_view_aside is decorated with @XBlockAside.aside_for("student_view"), so it is invoked whenever the runtime renders any block’s student_view.

A filter

should_apply_to_block restricts the Aside to Problem blocks.

An entry point

The xblock_asides.v1 entry point in pyproject.toml makes the Aside discoverable by the platform at startup.

Every production Aside has the same four pieces, plus additional features such as scoped fields, AJAX handlers, author-side UI, and template-rendered HTML.

Where to Go Next#

To turn this trivial example into something useful:

  • Add a course-author toggle. Declare a Boolean field with Scope.settings and conditionally render the banner based on its value. The Add an XBlock Aside how-to walks through this.

  • Render from a template. Replace the inline HTML string with a template loaded from your package’s static assets, rendered through the runtime’s template service.

  • Add an AJAX handler. Decorate a method with @XBlock.handler and call it from JavaScript in your fragment to support interactive behavior.

  • Decorate the author view. Add a second method decorated with @XBlockAside.aside_for("author_view") to render an author-facing preview in Studio.

For each of these extensions, the XBlock Asides Reference is the authoritative source. For the trade-offs and current limitations of the Aside mechanism, read About XBlock Asides before scaling up your design.

See also

About XBlock Asides (concept)

Why asides exist, what problem they solve, and current limitations.

Add an XBlock Aside (how-to)

A step-by-step recipe for adding an Aside to existing XBlocks.

XBlock Asides Reference (reference)

The complete API surface for XBlockAside and its runtime hooks.

Maintenance chart

Review Date

Working Group Reviewer

Release

Test situation