Keyboard UX
Focus Management Patterns
Use these patterns to keep keyboard and assistive-tech navigation predictable across modals, popovers, and long content pages.
Focus Rules
Apply these rules to all interactive flows.
- Keep a visible focus ring on every interactive control.
- Restore focus to the trigger after closing modal/sheet/popover.
- Do not trap keyboard users in non-modal surfaces.
- Add a skip link for large docs and dashboard pages.
Manual Test Pass
Quick QA flow before merge or release.
Press `Tab` through the full page and verify visual ring continuity.
Open and close each dialog/sheet; ensure focus returns to the initiating control.
Check that `Esc` closes expected overlays and leaves focus in a valid place.
Modal Focus Restore Pattern
TSX
1import { useRef } from "react"2import {3 Button,4 Modal,5 ModalContent,6 ModalHeader,7 ModalTitle,8 ModalDescription,9 ModalTrigger10} from "@glinui/ui"1112export function DeleteDialog() {13 const triggerRef = useRef<HTMLButtonElement | null>(null)1415 return (16 <Modal>17 <ModalTrigger asChild>18 <Button ref={triggerRef} variant="destructive">19 Delete project20 </Button>21 </ModalTrigger>22 <ModalContent23 onCloseAutoFocus={(event) => {24 event.preventDefault()25 triggerRef.current?.focus()26 }}27 >28 <ModalHeader>29 <ModalTitle>Delete project</ModalTitle>30 <ModalDescription>This action cannot be undone.</ModalDescription>31 </ModalHeader>32 </ModalContent>33 </Modal>34 )35}
Skip Link Pattern
TSX
1<a2 href="#main-content"3 className="sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-3 focus:py-2"4>5 Skip to content6</a>