-
Notifications
You must be signed in to change notification settings - Fork 67
Description
Hello, I'm a developer who has found overlay-kit to be incredibly useful. The declarative API has made managing overlay state a much more pleasant experience. I'd like to propose an enhancement to further this developer experience, specifically around accessibility.
The Problem
A core value of overlay-kit is abstracting away the boilerplate of overlay state management, as shown in the Code Comparison documentation.
However, to implement an accessible overlay, developers are still required to write repetitive boilerplate code to manage ARIA attributes.
Current Implementation:
function CurrentExample() {
// 1. Separate state needed for aria-expanded
const [isExpanded, setIsExpanded] = useState(false);
const dialogId = useId(); // 2. Manual ID linking
const handleOpen = () => {
setIsExpanded(true);
overlay.open(({ isOpen, close }) => (
<Dialog
id={dialogId}
open={isOpen}
onClose={() => {
close();
setIsExpanded(false); // 3. Manually update state on close
}}
/>
));
};
return (
<button
onClick={handleOpen}
aria-expanded={isExpanded}
aria-controls={dialogId}
>
Open Dialog
</button>
);
}This manual management can lead to mistakes, and is a bit of a departure from the simplicity that overlay-kit aims for.
Proposed Solution
I propose enhancing the overlay.open API to accept an optional triggerRef. When this ref is provided, overlay-kit would automatically manage the necessary ARIA attributes.
- Proposed API:
overlay.open(Controller, { triggerRef?: React.RefObject<Element> }) - How it would work:
- When
triggerRefis provided,overlay-kitinternally generates an ID for the overlay and links it to thetriggerRefelement'saria-controlsattribute. - When the overlay is opened, it sets
aria-expanded="true"on the triggerRef element. - When the overlay is closed, it sets
aria-expanded="false".
- When
The Ideal API
This feature would allow developers to forget about ARIA attribute management and focus purely on their component's logic, resulting in cleaner and more declarative code.
Proposed Implementation:
function ProposedExample() {
const triggerRef = useRef<HTMLButtonElement>(null);
const handleOpen = () => {
overlay.open(
({ isOpen, close }) => <Dialog open={isOpen} onClose={close} />,
{ triggerRef } // Just pass the ref, and accessibility is handled!
);
};
return (
<button ref={triggerRef} onClick={handleOpen}>
Open Dialog
</button>
);
}Benefits
- Eliminates boilerplate, allowing developers to be more productive.
- Automates ARIA implementation, reducing human error and ensuring a higher standard of accessibility out of the box.
- Extends the library's core value from "simplified state management" to a more holistic "simplified UI declaration."
This would be a non-breaking change, as the triggerRef option would be entirely opt-in. I believe this addition would significantly increase the value of overlay-kit.
I would love to hear the maintainers' thoughts on this proposal. I am also willing to contribute to a PR if this aligns with the project's roadmap.
Thank you!