diff --git a/src/routing/ActiveLink.ts b/src/routing/ActiveLink.ts index fe89d984c..3339b4dcd 100644 --- a/src/routing/ActiveLink.ts +++ b/src/routing/ActiveLink.ts @@ -8,6 +8,7 @@ import Router from './Router'; export interface ActiveLinkProperties extends LinkProperties { activeClasses: SupportedClassName[]; + ariaCurrent?: 'page' | 'step' | 'location' | 'date' | 'time' | true; isExact?: boolean; } @@ -23,7 +24,7 @@ export const ActiveLink = factory(function ActiveLink({ children }) { const { to, routerKey = 'router', params } = properties(); - let { activeClasses, isExact, classes = [], ...props } = properties(); + let { activeClasses, ariaCurrent, isExact, classes = [], ...props } = properties(); diffProperty('to', (current: ActiveLinkProperties, next: ActiveLinkProperties) => { if (current.to !== next.to) { @@ -57,10 +58,14 @@ export const ActiveLink = factory(function ActiveLink({ const context = router.getRoute(to); const isActive = context && paramsEqual(params, { ...context.params, ...context.queryParams }); const contextIsExact = context && context.isExact(); + const linkIsActive = isActive && (!isExact || contextIsExact); classes = Array.isArray(classes) ? classes : [classes]; - if (isActive && (!isExact || contextIsExact)) { + if (linkIsActive) { classes = [...classes, ...activeClasses]; + if (ariaCurrent !== undefined) { + props['aria-current'] = ariaCurrent === true ? 'true' : ariaCurrent; + } } props = { ...props, classes }; } diff --git a/tests/routing/unit/ActiveLink.ts b/tests/routing/unit/ActiveLink.ts index 74e1289da..2c279b0dc 100644 --- a/tests/routing/unit/ActiveLink.ts +++ b/tests/routing/unit/ActiveLink.ts @@ -83,6 +83,30 @@ describe('ActiveLink', () => { r.expect(template); }); + it('Should add and remove aria-current as the outlet match status changes', () => { + router.setPath('/other'); + const r = renderer(() => w(ActiveLink, { to: 'foo', activeClasses: ['foo'], ariaCurrent: 'page' }), { + middleware: [[getRegistry, mockGetRegistry]] + }); + const WrappedLink = wrap(Link); + r.expect(assertion(() => w(WrappedLink, { classes: [], to: 'foo' }))); + + router.setPath('/foo'); + r.expect(assertion(() => w(WrappedLink, { classes: ['foo'], to: 'foo', 'aria-current': 'page' }))); + + router.setPath('/other'); + r.expect(assertion(() => w(WrappedLink, { classes: [], to: 'foo' }))); + }); + + it('Should support true as an aria-current value', () => { + router.setPath('/foo'); + const r = renderer(() => w(ActiveLink, { to: 'foo', activeClasses: ['foo'], ariaCurrent: true }), { + middleware: [[getRegistry, mockGetRegistry]] + }); + const WrappedLink = wrap(Link); + r.expect(assertion(() => w(WrappedLink, { classes: ['foo'], to: 'foo', 'aria-current': 'true' }))); + }); + it('Should render the ActiveLink children when matching query params', () => { router.setPath('/query/path?query=query'); const r = renderer(