Skip to content

Commit 5098274

Browse files
committed
feat: add exactActive
1 parent 3332983 commit 5098274

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export default function App() {
144144
}
145145
```
146146

147-
The `<A>` tag also has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
147+
The `<A>` tag also has an `active` class if its href matches the current location, an `exactActive` class if its href matches the current location exactly and `inactive` class otherwise. **Note:** `active` and `exactActive` are mutually exclusive - there is no class merging! By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`). `exactActive` is particularly useful for links to the root route `/` which would match everything.
148148

149149

150150
| prop | type | description |
@@ -154,7 +154,8 @@ The `<A>` tag also has an `active` class if its href matches the current locatio
154154
| replace | boolean | If true, don't add a new entry to the browser history. (By default, the new page will be added to the browser history, so pressing the back button will take you to the previous route.) |
155155
| state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating | |
156156
| inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) |
157-
| activeClass | string | The class to show when the link is active |
157+
| activeClass | string | The class to show when the link is active, i.e. the current location _starts with_ `href` |
158+
| exactActiveClass | string | The class to show when the link matches the `href` exactly |
158159
| end | boolean | If `true`, only considers the link to be active when the curent location matches the `href` exactly; if `false`, check if the current location _starts with_ `href` |
159160

160161
### The Navigate Component

src/components.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,27 +208,33 @@ export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorEle
208208
state?: unknown;
209209
inactiveClass?: string;
210210
activeClass?: string;
211+
exactActiveClass?: string;
212+
/**
213+
* @deprecated end property deprecated in favor of 'exactActiveClass'
214+
*/
211215
end?: boolean;
212216
}
213217
export function A(props: AnchorProps) {
214-
props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
218+
props = mergeProps({ inactiveClass: "inactive", activeClass: "active", exactActiveClass: 'exactActive' }, props);
215219
const [, rest] = splitProps(props, [
216220
"href",
217221
"state",
218222
"class",
219223
"activeClass",
220224
"inactiveClass",
225+
"exactActiveClass",
221226
"end"
222227
]);
223228
const to = useResolvedPath(() => props.href);
224229
const href = useHref(to);
225230
const location = useLocation();
226231
const isActive = createMemo(() => {
227232
const to_ = to();
228-
if (to_ === undefined) return false;
233+
if (to_ === undefined) return [false, false];
229234
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
230235
const loc = normalizePath(location.pathname).toLowerCase();
231-
return props.end ? path === loc : loc.startsWith(path);
236+
// To be replaced with [loc.startsWith(path), path === loc] when end is patched out
237+
return [props.end ? path === loc : loc.startsWith(path), path === loc];
232238
});
233239

234240
return (
@@ -239,11 +245,12 @@ export function A(props: AnchorProps) {
239245
state={JSON.stringify(props.state)}
240246
classList={{
241247
...(props.class && { [props.class]: true }),
242-
[props.inactiveClass!]: !isActive(),
243-
[props.activeClass!]: isActive(),
248+
[props.inactiveClass!]: !isActive()[0],
249+
[props.activeClass!]: isActive()[0] && !isActive()[1],
250+
[props.exactActiveClass!]: isActive()[1],
244251
...rest.classList
245252
}}
246-
aria-current={isActive() ? "page" : undefined}
253+
aria-current={isActive()[1] ? "page" : undefined}
247254
/>
248255
);
249256
}

0 commit comments

Comments
 (0)