-
Notifications
You must be signed in to change notification settings - Fork 250
Developers Guide ‐ Menu
In Adapt Framework, a menu is a special type of ContentObject that displays navigation options to learners, allowing them to choose which pages or submenus to access. Menus serve as the primary navigation structure for courses.
Box Menu is the default menu plugin bundled with Adapt Framework. While other menu plugins can be installed and used, Box Menu provides the standard menu functionality for most courses.
Box Menu can be configured at two levels: course-level (global settings) and ContentObject-level (individual menu appearance). For complete configuration examples, see Box Menu's example.json.
-
Menu - A ContentObject with
"_type": "menu"that displays child items - Menu Items - ContentObjects (pages or nested menus) that appear as clickable tiles in the menu
- Grouped Items - Multiple menu items visually grouped under a shared heading
- Submenus - Nested menus that provide hierarchical navigation
- Locking - Menu items can be locked to control access and enforce sequential progression. See Locking objects with '_isLocked' and '_lockType' for details.
Course-level settings are defined in course.json and apply globally to all menus.
| Attribute | Type | Description | Default | Framework Version |
|---|---|---|---|---|
_globals._menu._boxMenu.itemCount |
String | Label template for item count. Use {{_nthChild}} and {{_totalChild}} placeholders |
"Item {{_nthChild}} of {{_totalChild}}" |
v5.0+ |
_globals._menu._boxMenu.durationLabel |
String | Label displayed before duration text | "Duration:" |
v5.0+ |
Example:
{
"_globals": {
"_menu": {
"_boxMenu": {
"itemCount": "Item {{_nthChild}} of {{_totalChild}}",
"durationLabel": "Duration:"
}
}
}
}Configure the appearance of the course-level menu (typically the home menu).
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_boxMenu._graphic |
Object | Logo image displayed above menu title | v5.0+ |
_boxMenu._backgroundImage |
Object | Background images for different screen sizes | v5.0+ |
_boxMenu._backgroundStyles |
Object | CSS background properties (size, repeat, position) | v5.0+ |
_boxMenu._menuHeader |
Object | Header configuration including text alignment, background, and minimum heights | v5.0+ |
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_boxMenu._graphic._src |
String | Path to logo image | v5.0+ |
_boxMenu._graphic.alt |
String | Alternative text for logo. Leave blank for decorative images | v5.0+ |
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_boxMenu._backgroundImage._xlarge |
String | Background image for extra large screens (HD laptop/desktop) | v5.0+ |
_boxMenu._backgroundImage._large |
String | Background image for large screens (laptop/desktop) | v5.0+ |
_boxMenu._backgroundImage._medium |
String | Background image for medium screens (tablet) | v5.0+ |
_boxMenu._backgroundImage._small |
String | Background image for small screens (mobile) | v5.0+ |
| Attribute | Type | Values | Description | Framework Version |
|---|---|---|---|---|
_boxMenu._backgroundStyles._backgroundRepeat |
String |
"", "repeat", "repeat-x", "repeat-y", "no-repeat"
|
Controls how background image repeats. Empty string uses browser default | v5.0+ |
_boxMenu._backgroundStyles._backgroundSize |
String |
"", "auto", "cover", "contain"
|
Resize behavior. cover: stretch/crop to fill container. contain: fit entire image visible | v5.0+ |
_boxMenu._backgroundStyles._backgroundPosition |
String |
"", "left top", "left center", "left bottom", "center top", "center center", "center bottom", "right top", "right center", "right bottom"
|
Position of background image. First value is horizontal, second is vertical | v5.0+ |
The _menuHeader object controls the appearance of the menu header area.
Text Alignment
| Attribute | Type | Values | Description | Framework Version |
|---|---|---|---|---|
_boxMenu._menuHeader._textAlignment._title |
String |
"", "left", "center", "right"
|
Alignment of menu title. Automatically reverses for RTL languages | v5.0+ |
_boxMenu._menuHeader._textAlignment._subtitle |
String |
"", "left", "center", "right"
|
Alignment of menu subtitle. Automatically reverses for RTL languages | v5.0+ |
_boxMenu._menuHeader._textAlignment._body |
String |
"", "left", "center", "right"
|
Alignment of menu body text. Automatically reverses for RTL languages | v5.0+ |
_boxMenu._menuHeader._textAlignment._instruction |
String |
"", "left", "center", "right"
|
Alignment of menu instruction text. Automatically reverses for RTL languages | v5.0+ |
Header Background Image and Styles
The header supports its own background image and styling, separate from the main menu background. Uses the same structure as the main background:
-
_boxMenu._menuHeader._backgroundImage- Same properties as main background (_xlarge,_large,_medium,_small) -
_boxMenu._menuHeader._backgroundStyles- Same properties as main background (_backgroundRepeat,_backgroundSize,_backgroundPosition)
Minimum Heights
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_boxMenu._menuHeader._minimumHeights._xlarge |
Number | Minimum height in pixels for extra large screens. Use to prevent background image cropping | v5.0+ |
_boxMenu._menuHeader._minimumHeights._large |
Number | Minimum height in pixels for large screens | v5.0+ |
_boxMenu._menuHeader._minimumHeights._medium |
Number | Minimum height in pixels for medium screens | v5.0+ |
_boxMenu._menuHeader._minimumHeights._small |
Number | Minimum height in pixels for small screens | v5.0+ |
Example:
{
"_boxMenu": {
"_graphic": {
"alt": "Course Logo",
"_src": "course/en/images/logo.png"
},
"_backgroundImage": {
"_xlarge": "course/en/images/menu-bg-xlarge.jpg",
"_large": "course/en/images/menu-bg-large.jpg",
"_medium": "course/en/images/menu-bg-medium.jpg",
"_small": "course/en/images/menu-bg-small.jpg"
},
"_backgroundStyles": {
"_backgroundSize": "cover",
"_backgroundRepeat": "no-repeat",
"_backgroundPosition": "center center"
},
"_menuHeader": {
"_textAlignment": {
"_title": "center",
"_subtitle": "center",
"_body": "left",
"_instruction": "left"
},
"_backgroundImage": {
"_xlarge": "course/en/images/header-bg.jpg",
"_large": "course/en/images/header-bg.jpg",
"_medium": "course/en/images/header-bg.jpg",
"_small": "course/en/images/header-bg.jpg"
},
"_backgroundStyles": {
"_backgroundSize": "cover",
"_backgroundRepeat": "no-repeat",
"_backgroundPosition": "center center"
},
"_minimumHeights": {
"_xlarge": 500,
"_large": 500,
"_medium": 400,
"_small": 200
}
}
}
}Individual menus (ContentObjects with "_type": "menu") can override the course-level menu header settings.
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_boxMenu._renderAsGroup |
Boolean | When true, renders this menu as a grouped set of items on the parent menu instead of a navigable submenu |
v5.0+ |
Note: Submenu ContentObjects can use the same _boxMenu properties as the course-level menu (background images, styles, header configuration) to customize their appearance.
Menu items are ContentObjects (typically pages) that appear as tiles in the menu. Standard ContentObject properties control their display:
| Attribute | Type | Description | Framework Version |
|---|---|---|---|
_id |
String | Unique identifier for the ContentObject | v5.0+ |
_parentId |
String | ID of parent menu. Use "course" for top-level items |
v5.0+ |
_type |
String |
"page" for navigable pages, "menu" for submenus |
v5.0+ |
title |
String | Item title (translatable) | v5.0+ |
displayTitle |
String | Title displayed in menu (translatable) | v5.0+ |
body |
String | Description text (translatable) | v5.0+ |
_graphic |
Object | Thumbnail image with src and alt properties |
v5.0+ |
linkText |
String | Text for the navigation link (translatable) | v5.0+ |
_linkIconClass |
String | CSS class for link icon (e.g., "icon-controls-right") |
v5.0+ |
_linkIconPosition |
String | Icon position: "left" or "right"
|
v5.0+ |
duration |
String | Estimated completion time (translatable) | v5.0+ |
_isLocked |
Boolean | When true, prevents navigation to this item. See locking documentation
|
v5.0+ |
{
"_id": "co-05",
"_parentId": "course",
"_type": "page",
"title": "Introduction",
"displayTitle": "Introduction",
"body": "Learn the basics in this introductory module",
"_graphic": {
"alt": "Introduction module",
"src": "course/en/images/intro-thumb.jpg"
},
"linkText": "View",
"_linkIconClass": "icon-controls-right",
"_linkIconPosition": "right",
"duration": "5 mins"
}Box Menu supports two ways to organize menu items: grouped items and submenus. While they may appear similar, they serve different purposes.
Grouped items visually organize related menu items under a shared heading on the same menu screen. Groups display title, body, and instruction text above their items but do not create separate navigable screens.
- Organize related pages under thematic headings
- Maintain all items on a single menu screen
- Provide context for a set of menu items without additional navigation
- Create a ContentObject with
"_type": "menu"as the group container - Set
"_boxMenu._renderAsGroup": trueon this ContentObject - Add child ContentObjects with
_parentIdmatching the group's_id
[
{
"_id": "module-1-group",
"_parentId": "course",
"_type": "menu",
"title": "Module 1: Foundations",
"displayTitle": "Module 1: Foundations",
"body": "Complete these foundational lessons",
"instruction": "Select a lesson to begin",
"_boxMenu": {
"_renderAsGroup": true
}
},
{
"_id": "co-10",
"_parentId": "module-1-group",
"_type": "page",
"title": "Lesson 1",
"displayTitle": "Getting Started",
"body": "Learn the basics"
},
{
"_id": "co-11",
"_parentId": "module-1-group",
"_type": "page",
"title": "Lesson 2",
"displayTitle": "Core Concepts",
"body": "Understand key principles"
}
]Submenus are navigable menus nested within other menus, creating a hierarchical navigation structure. Clicking a submenu item navigates to a new menu screen.
- Create multi-level course structures
- Organize large courses into sections
- Provide separate navigation contexts for different course modules
- Create a ContentObject with
"_type": "menu"as the submenu - Do NOT set
_renderAsGroup(or set it tofalse) - Add child ContentObjects with
_parentIdmatching the submenu's_id
[
{
"_id": "advanced-module",
"_parentId": "course",
"_type": "menu",
"title": "Advanced Topics",
"displayTitle": "Advanced Topics",
"body": "Explore advanced concepts",
"_graphic": {
"alt": "Advanced module",
"src": "course/en/images/advanced-thumb.jpg"
},
"linkText": "Explore"
},
{
"_id": "co-20",
"_parentId": "advanced-module",
"_type": "page",
"title": "Advanced Lesson 1",
"displayTitle": "Complex Systems",
"body": "Deep dive into complex topics"
}
]| Feature | Grouped Items | Submenus |
|---|---|---|
| Navigation | No navigation - items stay on same menu | Navigates to new menu screen |
| Visual Treatment | Items grouped under heading on parent menu | Appears as single clickable item on parent menu |
Use _renderAsGroup
|
true |
false or omitted |
| Displays group title/body | Yes, above grouped items | Yes, when navigated to submenu |
| Typical Use Case | Thematic grouping on one screen | Hierarchical navigation structure |
Understanding the menu architecture helps when configuring courses or creating custom menu plugins.
Adapt Framework provides base classes in the core:
-
MenuModel (src/core/js/models/menuModel.js) - Extends
ContentObjectModel. Handles menu-specific logic including locking behavior via_isLockedand_lockType -
MenuView (src/core/js/views/menuView.js) - Extends
ContentObjectView. Base class for rendering menu layouts - MenuItemView (src/core/js/views/menuItemView.js) - Base class for rendering individual menu items
Box Menu extends these core classes:
-
BoxMenuModel - Extends
MenuModelfor Box Menu-specific model logic -
BoxMenuView - Extends
MenuView. Renders the menu container and determines whether items render as groups or standard items -
BoxMenuItemView - Extends
MenuItemView. Renders individual clickable menu items -
BoxMenuGroupView - Extends
MenuItemView. Renders grouped items with a heading
Menu plugins register with the framework's component system. Box Menu uses a dual registration to support both explicit and default usage:
// Default menu for "_type": "course" or "_type": "menu"
components.register('course menu', {
view: BoxMenuView,
model: BoxMenuModel
});
// Explicit usage with "_component": "boxMenu"
components.register('boxMenu', {
view: BoxMenuView,
model: BoxMenuModel
});- Framework encounters a ContentObject with
"_type": "menu" - Looks up registered menu view/model (defaults to Box Menu if installed)
- Creates menu view instance, which renders menu header and container
- For each child ContentObject:
- If child has
"_type": "menu"and"_renderAsGroup": true, renders asBoxMenuGroupView - Otherwise, renders as
BoxMenuItemView
- If child has
- Menu items become clickable and navigate via the router
While Box Menu handles most use cases, you may want to create a custom menu plugin for unique navigation requirements or visual designs.
A menu plugin requires:
-
Model class extending
MenuModel -
View class extending
MenuView -
Item view class extending
MenuItemView(optional, can use core'sMenuItemView) -
Registration via
components.register() - Templates (JSX or Handlebars)
- Schema files for configuration options
import components from 'core/js/components';
import MenuView from 'core/js/views/menuView';
import MenuModel from 'core/js/models/menuModel';
class MyMenuView extends MenuView {
className() {
return `${super.className()} mymenu`;
}
}
MyMenuView.template = 'myMenu.jsx';
components.register('course menu', {
view: MyMenuView,
model: MenuModel
});
export default MyMenuView;import React from 'react';
import { html, classes, compile } from 'core/js/reactHelpers';
export default function MyMenu(props) {
const { displayTitle, body } = props;
return (
<div className="mymenu__inner">
<div className="mymenu__header">
{displayTitle && <h1 className="mymenu__title">{displayTitle}</h1>}
{body && <div className="mymenu__body">{html(compile(body, props))}</div>}
</div>
<div className="mymenu__items js-children"></div>
</div>
);
}-
childContainer - Set
static childContainer = '.js-children'to specify where child items render -
childView - Set
static childView = MenuItemViewor your custom item view class -
Templates - The
js-childrenelement is where framework injects menu items - Styling - Add custom LESS files for visual design
- Schemas - Define configuration options in schema/*.schema.json files
If you need custom rendering for menu items, always check _isLocked before allowing navigation:
import MenuItemView from 'core/js/views/menuItemView';
import router from 'core/js/router';
class MyMenuItemView extends MenuItemView {
events() {
return {
'click .js-item-click': 'onItemClick'
};
}
onItemClick(event) {
event?.preventDefault();
// Always respect locking - see locking documentation for details
if (this.model.get('_isLocked')) return;
router.navigateToElement(this.model.get('_id'));
}
}
MyMenuItemView.template = 'myMenuItem.jsx';
export default MyMenuItemView;Define custom options in schema/course.schema.json and/or schema/contentobject.schema.json. See Box Menu's schema files for examples of property definitions.
-
Locking objects - Locking objects with
_isLockedand_lockType. Control menu item access and enforce sequential progression - Adapt Framework Wiki - Full framework documentation
- Box Menu - Source code and issues
Note: For information about specific releases and features, see the Box Menu releases page.
- Framework in Five Minutes
- Setting up Your Development Environment
- Manual Installation of the Adapt Framework
- Adapt Command Line Interface
- Common Issues
- Reporting Bugs
- Requesting Features
- Creating Your First Course
- Styling Your Course
- Configuring Your Project with config.json
- Content starts with course.json
- Course Localisation
- Compiling, testing and deploying your Adapt course
- Core Plugins in the Adapt Learning Framework
- Converting a Course from Framework Version 1 to Version 2
- Contributing to the Adapt Project
- Git Flow
- Adapt API
- Core Events
- Core Model Attributes
- Core Modules
- States and Indicators
- Right to Left (RTL) Support
- Web Security Audit
- Peer Code Review
- Plugins
- Developing Plugins
- Developer's Guide: Components
- Developer's Guide: Theme
- Making a theme editable
- Developer's Guide: Menu
- Registering a Plugin
- Semantic Version Numbers
- Migration scripts