diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 089900fb77..35c61f2f16 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -71,6 +71,7 @@ import {
} from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import {
+ ExpandableNavigation,
ReportIssue,
TextSize,
} from '@backstage/plugin-techdocs-module-addons-contrib';
@@ -185,6 +186,7 @@ const routes = (
>
{techDocsPage}
+
diff --git a/plugins/techdocs-module-addons-contrib/api-report.md b/plugins/techdocs-module-addons-contrib/api-report.md
index 19d2f70a2b..4a93356365 100644
--- a/plugins/techdocs-module-addons-contrib/api-report.md
+++ b/plugins/techdocs-module-addons-contrib/api-report.md
@@ -7,6 +7,9 @@
import { BackstagePlugin } from '@backstage/core-plugin-api';
+// @public
+export const ExpandableNavigation: (props: unknown) => JSX.Element | null;
+
// @public
export const ReportIssue: (props: ReportIssueProps) => JSX.Element | null;
diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json
index 8a1801f0ba..074d12a505 100644
--- a/plugins/techdocs-module-addons-contrib/package.json
+++ b/plugins/techdocs-module-addons-contrib/package.json
@@ -43,6 +43,7 @@
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
+ "@react-hookz/web": "^13.0.0",
"git-url-parse": "^11.6.0",
"react-use": "^17.2.4"
},
diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx
new file mode 100644
index 0000000000..486ddcd267
--- /dev/null
+++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { useEffect, useState } from 'react';
+import { useLocalStorageValue } from '@react-hookz/web';
+import { Button, withStyles } from '@material-ui/core';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+
+import { useShadowRoot } from '@backstage/plugin-techdocs-react';
+
+const NESTED_LIST_TOGGLE = '.md-nav__item--nested .md-toggle';
+
+const EXPANDABLE_NAVIGATION_LOCAL_STORAGE =
+ '@backstage/techdocs-addons/nav-expanded';
+
+const StyledButton = withStyles({
+ root: {
+ position: 'absolute',
+ left: '220px',
+ top: '19px',
+ padding: 0,
+ minWidth: 0,
+ },
+})(Button);
+
+const CollapsedIcon = withStyles({
+ root: {
+ height: '20px',
+ width: '20px',
+ },
+})(ChevronRightIcon);
+
+const ExpandedIcon = withStyles({
+ root: {
+ height: '20px',
+ width: '20px',
+ },
+})(ExpandMoreIcon);
+
+type expandableNavigationLocalStorage = {
+ navExpanded: boolean;
+};
+
+export const ExpandableNavigationAddon = () => {
+ const shadowRoot = useShadowRoot();
+ const defaultValue = { navExpanded: false };
+ const [expanded, setExpanded] =
+ useLocalStorageValue(
+ EXPANDABLE_NAVIGATION_LOCAL_STORAGE,
+ defaultValue,
+ );
+ const [hasNavSubLevels, setHasNavSubLevels] = useState(false);
+
+ useEffect(() => {
+ const checkboxToggles =
+ shadowRoot?.querySelectorAll(NESTED_LIST_TOGGLE);
+ if (!checkboxToggles || (checkboxToggles && checkboxToggles.length === 0))
+ return;
+ setHasNavSubLevels(true);
+ checkboxToggles.forEach(item => {
+ if (
+ (expanded?.navExpanded && !item.checked) ||
+ (!expanded?.navExpanded && item.checked)
+ ) {
+ item.click();
+ }
+ });
+ }, [shadowRoot, expanded]);
+
+ const handleState = () => {
+ setExpanded(prevState => ({
+ navExpanded: !prevState?.navExpanded,
+ }));
+ };
+
+ return (
+ <>
+ {hasNavSubLevels ? (
+
+ {expanded?.navExpanded ? : }
+
+ ) : null}
+ >
+ );
+};
diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts
new file mode 100644
index 0000000000..8f1c131d08
--- /dev/null
+++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './ExpandableNavigation';
diff --git a/plugins/techdocs-module-addons-contrib/src/index.ts b/plugins/techdocs-module-addons-contrib/src/index.ts
index e2e57b15d1..528afe5c0d 100644
--- a/plugins/techdocs-module-addons-contrib/src/index.ts
+++ b/plugins/techdocs-module-addons-contrib/src/index.ts
@@ -22,6 +22,7 @@
export {
techdocsModuleAddonsContribPlugin,
+ ExpandableNavigation,
ReportIssue,
TextSize,
} from './plugin';
diff --git a/plugins/techdocs-module-addons-contrib/src/plugin.ts b/plugins/techdocs-module-addons-contrib/src/plugin.ts
index 0d7743da9e..dbef119da8 100644
--- a/plugins/techdocs-module-addons-contrib/src/plugin.ts
+++ b/plugins/techdocs-module-addons-contrib/src/plugin.ts
@@ -19,6 +19,7 @@ import {
createTechDocsAddonExtension,
TechDocsAddonLocations,
} from '@backstage/plugin-techdocs-react';
+import { ExpandableNavigationAddon } from './ExpandableNavigation';
import { ReportIssueAddon, ReportIssueProps } from './ReportIssue';
import { TextSizeAddon } from './TextSize';
@@ -32,6 +33,20 @@ export const techdocsModuleAddonsContribPlugin = createPlugin({
id: 'techdocsModuleAddonsContrib',
});
+/**
+ * TechDocs addon that lets you expand/collapse the TechDocs main navigation.
+ *
+ * @public
+ */
+
+export const ExpandableNavigation = techdocsModuleAddonsContribPlugin.provide(
+ createTechDocsAddonExtension({
+ name: 'ExpandableNavigation',
+ location: TechDocsAddonLocations.PrimarySidebar,
+ component: ExpandableNavigationAddon,
+ }),
+);
+
/**
* TechDocs addon that lets you select text and open GitHub/Gitlab issues
*