diff --git a/README.md b/README.md index a156b514e..d31b0086a 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ export default function App() { } ``` -The `` 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. +The `` tag also has an `active` class if its href matches the current location and `inactive` class otherwise. By providing the property `exactActiveClass`, you can opt in to a third state, which is `exactActive` and is set when the href matches the current location exactly. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`). If no `exactActiveClass` property was provided, `active` class will be set for both partially and exactly matching routes. | prop | type | description | @@ -154,8 +154,9 @@ The `` tag also has an `active` class if its href matches the current locatio | 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.) | | state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating | | | inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) | -| activeClass | string | The class to show when the link is active | -| 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` | +| activeClass | string | The class to show when the link is active, i.e. the current location _starts with_ `href` | +| exactActiveClass | string or true | The class to show when the link matches the `href` exactly. If `true`, applies `exactActive` class and enables strict matching - i.e. `activeClass` will not apply for an exact match. +| end | boolean | **Deprecated** 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` - providing `exactActiveClass` overrides this behavior | | ### The Navigate Component Solid Router provides a `Navigate` component that works similarly to `A`, but it will _immediately_ navigate to the provided path as soon as the component is rendered. It also uses the `href` prop, but you have the additional option of passing a function to `href` that returns a path to navigate to: diff --git a/src/components.tsx b/src/components.tsx index 095339bce..08840f62c 100644 --- a/src/components.tsx +++ b/src/components.tsx @@ -208,6 +208,10 @@ export interface AnchorProps extends Omit props.href); const href = useHref(to); const location = useLocation(); - const isActive = createMemo(() => { + const matchedHref = createMemo(() => { const to_ = to(); - if (to_ === undefined) return false; + if (to_ === undefined) return [false, false]; const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase(); const loc = normalizePath(location.pathname).toLowerCase(); - return props.end ? path === loc : loc.startsWith(path); + return [loc.startsWith(path), path === loc]; }); + const isLooseMatch = createMemo(() => matchedHref()[0]) + const isExactMatch = createMemo(() => matchedHref()[1] && Boolean(props.exactActiveClass)) + + // Remove together with `end` property + // If end was provided return an exact match, else return loose match (as long as users don't opt in for new behavior) + const isActiveDeprecated = createMemo(() => props.end ? matchedHref()[1] : !props.exactActiveClass && isLooseMatch()) + return ( ); }