Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/components_page/components/nav.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Use the `vertical` argument to stack navigation items. You can pass either a Boo

## Pills

Use the `pills` argument to indicate active state with pill styled nav items.
Use the `pills` argument to indicate active state with pill styled nav items. The `active` property can be set to `True` or `False` to manually control whether the link is active, or to `"exact"` to automatically set the `active` property when the current pathname matches the `href`, or to `"partial"` to automatically set the `active` property when the current pathname starts with `href`.

{{example:components/nav/pill.py:nav}}

Expand Down
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"@plotly/dash-component-plugins": "^1.2.0",
"classnames": "^2.2.6",
"fast-isnumeric": "^1.1.3",
"is-absolute-url": "^2.1.0",
Expand Down
44 changes: 40 additions & 4 deletions src/components/nav/NavLink.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import {omit} from 'ramda';
import classNames from 'classnames';
import {History} from '@plotly/dash-component-plugins';
import Link from '../../private/Link';

/**
* Add a link to a `Nav`. Can be used as a child of `NavItem` or of `Nav`
* directly.
*/
const NavLink = props => {
const [linkActive, setLinkActive] = useState(false);
const {
children,
disabled,
Expand All @@ -17,9 +19,18 @@ const NavLink = props => {
loading_state,
setProps,
n_clicks,
href,
...otherProps
} = props;

const pathnameToActive = pathname => {
setLinkActive(
active === true ||
(active === 'exact' && pathname === href) ||
(active === 'partial' && pathname.startsWith(href))
);
};

const incrementClicks = () => {
if (!disabled && setProps) {
setProps({
Expand All @@ -29,12 +40,24 @@ const NavLink = props => {
}
};

const classes = classNames(className, 'nav-link', {active, disabled});
useEffect(() => {
// get initial pathname
pathnameToActive(window.location.pathname);

// add event listener to update on change
History.onChange(() => pathnameToActive(window.location.pathname));
}, []);

const classes = classNames(className, 'nav-link', {
active: linkActive,
disabled
});
return (
<Link
className={classes}
disabled={disabled}
preOnClick={incrementClicks}
href={href}
{...omit(['n_clicks_timestamp'], otherProps)}
data-dash-is-loading={
(loading_state && loading_state.is_loading) || undefined
Expand Down Expand Up @@ -88,9 +111,22 @@ NavLink.propTypes = {
href: PropTypes.string,

/**
* Apply 'active' style to this component
* Apply 'active' style to this component. Set to "exact" to automatically
* toggle active status when the current pathname matches href, or to
* "partial" to automatically toggle on a partial match. Assumes that href is
* a relative url such as /link rather than an absolute such as
* https://example.com/link
*
* For example
* - dbc.NavLink(..., href="/my-page", active="exact") will be active on
* "/my-page" but not "/my-page/other" or "/random"
* - dbc.NavLink(..., href="/my-page", active="partial") will be active on
* "/my-page" and "/my-page/other" but not "/random"
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is worth having an explanation of the format an href must take? From what I can see this doesn't account for someone using http://...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a good call. I'll try to clarify the docstring / documentation.

active: PropTypes.bool,
active: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['partial', 'exact'])
]),

/**
* Disable the link
Expand Down