Skip to content

[6.x] Sidebar nav renders an <li> inside an <li> on every Control Panel page #15395

Description

@bpmore

Bug description

The CP sidebar renders an <li> directly inside another <li> on every authenticated Control Panel page.

Nav.vue wraps each nav item in an <li>, then drops the item's Blade view HTML inside it:

https://github.com/statamic/cms/blob/v6.31.0/resources/js/components/nav/Nav.vue#L206
https://github.com/statamic/cms/blob/v6.31.0/resources/js/components/nav/Nav.vue#L207

Two core nav views open with their own <li>:

https://github.com/statamic/cms/blob/v6.31.0/resources/views/nav/updates.blade.php#L5
https://github.com/statamic/cms/blob/v6.31.0/resources/views/nav/duplicates.blade.php#L5

Rendered result:

main#main > nav.nav-main > div > ul > li > li

An <li> whose parent is an <li> is not part of any list, so the item drops out of the list structure. Screen readers announce the wrong item count for the navigation and may skip the affected entry when navigating by list.

axe-core reports listitem (serious) on 44 of 44 authenticated screens scanned.

WCAG 2.1 SC 1.3.1 Info and Relationships (Level A).

How to reproduce

  1. composer create-project statamic/statamic, create a super user, log in
  2. On any CP page, run in the console:
[...document.querySelectorAll('li')].filter(li => li.parentElement.tagName === 'LI')

Returns the Updates nav item on every page.

Suggested fix

Remove the wrapping <li> from resources/views/nav/updates.blade.php and resources/views/nav/duplicates.blade.php, since Nav.vue already supplies one.

Two lines. This is the highest-reach single fix in the accessibility audit this came from: it clears a Level A violation on every page in the CP.

Worth documenting the contract for addon nav views too, so third-party ->view() items don't reintroduce it.

Environment

Environment
Laravel Version: 13.30.1
PHP Version: 8.4.23
Composer Version: 2.10.2
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: log
Queue: sync
Session: file

Storage
public/storage: NOT LINKED

Statamic
Addons: 0
License Key: Not set
Sites: 1
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.31.0 PRO

Installation

Fresh statamic/statamic site via CLI

Additional details

Found during a WCAG 2.1 AA audit of a vanilla composer create-project statamic/statamic install with no addons and no custom code. Tested with axe-core 4.x on Chromium 153 at 1440x1000, plus manual keyboard traversal. Source references point at v6.31.0.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions