Skip to content

Conversation

@swashbuck
Copy link
Contributor

@swashbuck swashbuck commented Jan 8, 2026

Fix #816

📋 To-do

New

  • Adds priority labels to headings. Includes menu items, content objects, articles, blocks, and component headings.

Notes

  • Can be configured to show optional labels, required labels, both, or none.
  • Each content type can have different behavior for showing priority labels
  • Priority label settings can be overridden on specific instances. For instance, you can disable labels globally for blocks but then show them for a specific block.
  • Classes have been added so that the type of priority label can be styled differently (e.g. red labels for required and orange for optional)
  • Priority labels only appear when a displayed title is present on the item.

Dependencies

Configuration

In course.json, add the following to _globals and enable/disable labels as desired.

The following example configuration will show optional labels only for menu item and page headings. In contentObjects.json, set "_isOptional": true to make content objects optional.

"_priorityLabels": {
  "_iconClassOptional": "",
  "_iconClassRequired": "icon-exclamation",
  "_menuItem": {
    "_showWhenOptional": true,
    "_showWhenRequired": false
  },
  "_page": {
    "_showWhenOptional": true,
    "_showWhenRequired": false
  },
  "_article": {
    "_showWhenOptional": false,
    "_showWhenRequired": false
  },
  "_block": {
    "_showWhenOptional": false,
    "_showWhenRequired": false
  },
  "_component": {
    "_showWhenOptional": false,
    "_showWhenRequired": false
  }
},

You can also override global priority label settings for individual elements. Add to the specific instance (ex. a block):

"_priorityLabels": {
    "_isOverride": true,
    "_showWhenRequired": true,
    "_showWhenOptional": false
},

@swashbuck
Copy link
Contributor Author

Ready for review.

@oliverfoster
Copy link
Member

Should the icons be defined in the json? I'm not sure what the standard is there. CSS only or json define class name?

@swashbuck
Copy link
Contributor Author

swashbuck commented Jan 12, 2026

Should the icons be defined in the json? I'm not sure what the standard is there. CSS only or json define class name?

I like the idea of setting this in the JSON config. This could be two new props that would apply to all types (box menu item, article, etc). I don't feel that we would need a different icon for each type. So, we would have:

"_priorityLabels": {
  "_iconClassOptional": "", // no icon for optional
  "_iconClassRequired": "icon-exclamation", // exclamation mark for required
  "_menuItem": {
    "_showWhenOptional": true,
    "_showWhenRequired": false
  },
  "_page": {
    "_showWhenOptional": true,
    "_showWhenRequired": false
  },
  etc.....

Thoughts about this approach? We would need to remove it from the Vanilla theme PR as the icon is currently hard-coded in the Less.

@swashbuck
Copy link
Contributor Author

@kirsty-hames Any thoughts on the icon config proposed solution?

@kirsty-hames
Copy link
Contributor

"_priorityLabels": {
"_iconClassOptional": "", // no icon for optional
"_iconClassRequired": "icon-exclamation", // exclamation mark for required

@kirsty-hames Any thoughts on the icon config proposed solution?

I'm happy with the above suggestion thanks @swashbuck. When I've seen optional/progress labels used in projects, I've only seen icons used as suggested (no icon for optional, exclamation mark for required). Whilst I can't see much scope for changing the icons at least it's future proofing for customisation.

@kirsty-hames
Copy link
Contributor

kirsty-hames commented Jan 15, 2026

Hey @swashbuck, just thinking on this from an a11y perspective, whilst the optional/required labels are accessible, they don't have context of the content they refer to. As per my suggestion in the PLP optional content visual indicator PR, is it worth adding the optional / required labels to the model headings like we already do for complete/incomplete?

Alternatively, we could add the model title to the optional/required labels as hidden labels. However, I think it makes sense to update the model headings for the following reasons:

  • headings are often used as landmarks to navigate page content by SR users so heading level labels would mean a learner could easily identify optional/required content
  • consistency with the existing complete/incomplete labels we add to headings
  • avoid duplicate reading of title text when linear reading through a page

If we did do this then we should set the priority labels to aria-hidden="true" to avoid duplicate reading when a model title exists.

swashbuck and others added 3 commits January 19, 2026 14:20
Co-authored-by: Joseph Replin <joe.replin@kineo.com>
@swashbuck
Copy link
Contributor Author

Icon classes have been implemented.

is it worth adding the optional / required labels to the model headings like we already do for complete/incomplete?

@kirsty-hames I think this makes sense. Would we only show optional / required when the relevant priority labels are configured to be shown? In other words, only show optional when _showWhenOptional is true for that type (ex. box menu item, component)?

Also, this is how the titles could be read. Is this what you had in mind?

Content Type Heading Announcement
Optional incomplete "Optional. [Title]"
Optional complete "Optional. Complete. [Title]"
Required incomplete "Required. Incomplete. [Title]"
Required complete "Required. Complete. [Title]"

@kirsty-hames
Copy link
Contributor

Would we only show optional / required when the relevant priority labels are configured to be shown?

Thanks @swashbuck. Yep this is what I had in mind. If an on screen label doesn't exist then there's no reason to provide the alt text equivalent.

@swashbuck
Copy link
Contributor Author

swashbuck commented Jan 20, 2026

Thanks, @kirsty-hames .

When a displayTitle isn't present:

  1. Should we show the priority label at all? Currently, it's shown as long as there is a displayTitle, body text, or instruction text. So, an optional Graphic without any text will not show the label.
  2. If we do show the label when there is no title, how should we announce the status to assistive technologies? Would they read the onscreen label or would we add a new AT-only span tag?

Screenshots showing 3 optional components: Text, MCQ and Graphic. Note that the label is not shown for the optional Graphic.

@kirsty-hames
Copy link
Contributor

When a displayTitle isn't present:

  1. Should we show the priority label at all? Currently, it's shown as long as there is a displayTitle, body text, or instruction text. So, an optional Graphic without any text will not show the label.
  2. If we do show the label when there is no title, how should we announce the status to assistive technologies? Would they read the onscreen label or would we add a new AT-only span tag?

Good points @swashbuck. I'm open to either but my preference would be to only display the priority label when displayTitle is present. A couple of reasons why:

  • From an a11y perspective, I think all required content should have a title so users can easily evaluate and navigate required content. Less of an issue for optional content.
  • Flexibility in content layout. For example, the MCQ and Graphic instance you've provided above, a double up on labels is unnecessary and adds visual clutter.

@swashbuck
Copy link
Contributor Author

swashbuck commented Jan 22, 2026

Thanks, @kirsty-hames. I agree on both points. That said, I can think of one use case that might be a problem: when we use a block header to replace the component header. For example:

Block header with "MCQ" title and body text
Single width MCQ with no displayed title / body text Single width Graphic

But we probably wouldn't want the priority label to be positioned above the title-less MCQ component either. Maybe we shouldn't worry about this edge case, although we do often use this layout. Could also use block priority labels instead of component labels in this case.

With block priority labels enabled:
Screenshot 2026-01-22 at 11 05 13 AM

@kirsty-hames
Copy link
Contributor

Thanks, @kirsty-hames. I agree on both points. That said, I can think of one use case that might be a problem: when we use a block header to replace the component header. For example:

Block header with "MCQ" title and body text
Single width MCQ with no displayed title / body text Single width Graphic
But we probably wouldn't want the priority label to be positioned above the title-less MCQ component either. Maybe we shouldn't worry about this edge case, although we do often use this layout. Could also use block priority labels instead of component labels in this case.

Hey @swashbuck, I also find this is a common layout use case and agree in this instance it would make sense to enable the priority label at block level. My only concern with this is the current config is limited to model only (all blocks etc) - there's no option to override per block instance. So would this mean the priority labels would need to be enabled for all blocks to support the scenario you've screenshotted above?

@swashbuck
Copy link
Contributor Author

swashbuck commented Jan 26, 2026

Hey @swashbuck, I also find this is a common layout use case and agree in this instance it would make sense to enable the priority label at block level. My only concern with this is the current config is limited to model only (all blocks etc) - there's no option to override per block instance. So would this mean the priority labels would need to be enabled for all blocks to support the scenario you've screenshotted above?

Yep, this would definitely be an issue. Is it worth allowing individual elements the ability to override global settings? So, if we had block priority labels disabled globally, the specific block in the above screenshot could override with:

"_priorityLabels": {
    "_isOverride": true,
    "_showWhenRequired": true,
    "_showWhenOptional": false,
},

@kirsty-hames
Copy link
Contributor

kirsty-hames commented Jan 26, 2026

Yep, this would definitely be an issue. Is it worth allowing individual elements the ability to override global settings? So, if we had block priority labels disabled globally, the specific block in the above screenshot could override with:

"_priorityLabels": {
    "_isOverride": true,
    "_showWhenRequired": true,
    "_showWhenOptional": false,
},

Thanks @swashbuck. In most instances, priority labels will only require global settings but at least when we do set an override it's super clear.

@swashbuck
Copy link
Contributor Author

Overrides at the element level have been added.

I believe all that's left is the migration scripts, and I'm waiting on #824 to be approved.

@swashbuck swashbuck moved this from Needs Reviewing to Assigned in adapt_framework: The TODO Board Jan 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

Add priority labels to headings

5 participants