@@ -545,7 +545,8 @@ export default {
545545 As a simple solution - render it in the content to keep correct position.
546546 -->
547547 <Teleport v-if =" ncContentSelector && !open && !noToggle" :selector =" ncContentSelector" >
548- <NcButton :aria-label =" t('Open sidebar')"
548+ <NcButton ref =" toggle"
549+ :aria-label =" t('Open sidebar')"
549550 class =" app-sidebar__toggle"
550551 :class =" toggleClasses"
551552 variant =" tertiary"
@@ -613,17 +614,13 @@ export default {
613614 <div class =" app-sidebar-header__name-container" >
614615 <div class =" app-sidebar-header__mainname-container" >
615616 <!-- main name -->
616- <h2 v-show =" !nameEditable"
617- :id =" `app-sidebar-vue-${uid}__header`"
618- ref =" header"
619- v-linkify =" {text: name, linkify: linkifyName}"
620- :aria-label =" title"
621- :title =" title"
617+ <NcAppSidebarHeader v-show =" !nameEditable"
622618 class =" app-sidebar-header__mainname"
619+ :name =" name"
620+ :linkify =" linkifyName"
621+ :title =" title"
623622 :tabindex =" nameEditable ? 0 : -1"
624- @click.self =" editName" >
625- {{ name }}
626- </h2 >
623+ @click.self.native =" editName" />
627624 <template v-if =" nameEditable " >
628625 <form v-click-outside =" () => onSubmitName()"
629626 class =" app-sidebar-header__mainname-form"
@@ -664,6 +661,11 @@ export default {
664661 </div >
665662 </div >
666663 </div >
664+ <!-- a11y fallback for empty content -->
665+ <NcAppSidebarHeader v-if =" empty"
666+ class =" app-sidebar-header__mainname--hidden"
667+ :name =" name"
668+ tabindex =" -1" />
667669
668670 <NcButton ref =" closeButton"
669671 :aria-label =" closeTranslated"
@@ -704,11 +706,11 @@ import { Portal as Teleport } from '@linusborg/vue-simple-portal'
704706
705707import NcAppSidebarTabs from ' ./NcAppSidebarTabs.vue'
706708import NcActions from ' ../NcActions/index.js'
709+ import NcAppSidebarHeader from ' ../NcAppSidebarHeader/index.ts'
707710import NcButton from ' ../NcButton/index.js'
708711import NcEmptyContent from ' ../NcEmptyContent/index.js'
709712import NcLoadingIcon from ' ../NcLoadingIcon/index.js'
710713import Focus from ' ../../directives/Focus/index.js'
711- import Linkify from ' ../../directives/Linkify/index.js'
712714import { useIsSmallMobile } from ' ../../composables/useIsMobile/index.js'
713715import GenRandomId from ' ../../utils/GenRandomId.js'
714716import { getTrapStack } from ' ../../utils/focusTrap.ts'
@@ -722,13 +724,15 @@ import StarOutline from 'vue-material-design-icons/StarOutline.vue'
722724
723725import { vOnClickOutside as ClickOutside } from ' @vueuse/components'
724726import { createFocusTrap } from ' focus-trap'
727+ import Vue , { provide , ref } from ' vue'
725728
726729export default {
727730 name: ' NcAppSidebar' ,
728731
729732 components: {
730733 Teleport,
731734 NcActions,
735+ NcAppSidebarHeader,
732736 NcAppSidebarTabs,
733737 ArrowRight,
734738 IconDockRight,
@@ -742,7 +746,6 @@ export default {
742746
743747 directives: {
744748 focus: Focus,
745- linkify: Linkify,
746749 ClickOutside,
747750 },
748751
@@ -923,9 +926,13 @@ export default {
923926 ],
924927
925928 setup () {
929+ const headerRef = ref (null )
930+ provide (' NcAppSidebar:header:ref' , headerRef)
931+
926932 return {
927933 uid: GenRandomId (),
928934 isMobile: useIsSmallMobile (),
935+ headerRef,
929936 }
930937 },
931938
@@ -1155,7 +1162,16 @@ export default {
11551162 * @public
11561163 */
11571164 focus () {
1158- this .$refs .header .focus ()
1165+ if (! this .open && ! this .noToggle ) {
1166+ this .$refs .toggle .$el .focus ()
1167+ return
1168+ }
1169+
1170+ try {
1171+ this .headerRef .focus ()
1172+ } catch {
1173+ Vue .util .warn (' NcAppSidebar should have focusable header for accessibility reasons. Use NcAppSidebarHeader component.' )
1174+ }
11591175 },
11601176
11611177 /**
@@ -1517,6 +1533,17 @@ $top-buttons-spacing: $app-navigation-padding; // align with app navigation
15171533 }
15181534 }
15191535
1536+ // Hidden a11y fallback
1537+ .app - sidebar- header__mainname-- hidden {
1538+ position: absolute;
1539+ top: 0 ;
1540+ inset- inline- start: 0 ;
1541+ margin: 0 ;
1542+ width: 1px ;
1543+ height: 1px ;
1544+ overflow: hidden;
1545+ }
1546+
15201547 // sidebar description slot
15211548 & __description {
15221549 display: flex;
0 commit comments