diff --git a/dotcom-rendering/src/components/FrontPage.tsx b/dotcom-rendering/src/components/FrontPage.tsx
index 56a573685fa..6aee8c43824 100644
--- a/dotcom-rendering/src/components/FrontPage.tsx
+++ b/dotcom-rendering/src/components/FrontPage.tsx
@@ -17,7 +17,6 @@ import { Metrics } from './Metrics.importable';
import { ReaderRevenueDev } from './ReaderRevenueDev.importable';
import { SetABTests } from './SetABTests.importable';
import { SetAdTargeting } from './SetAdTargeting.importable';
-import { ShowHideContainers } from './ShowHideContainers.importable';
import { SkipTo } from './SkipTo';
type Props = {
@@ -71,13 +70,6 @@ export const FrontPage = ({ front, NAV }: Props) => {
tests={front.config.abTests}
/>
-
-
-
-
+
+
+
)}
diff --git a/dotcom-rendering/src/components/Island.test.tsx b/dotcom-rendering/src/components/Island.test.tsx
index 074c1dc4054..c01bf118336 100644
--- a/dotcom-rendering/src/components/Island.test.tsx
+++ b/dotcom-rendering/src/components/Island.test.tsx
@@ -31,7 +31,7 @@ import { SendTargetingParams } from './SendTargetingParams.importable';
import { SetABTests } from './SetABTests.importable';
import { SetAdTargeting } from './SetAdTargeting.importable';
import { ShareButton } from './ShareButton.importable';
-import { ShowHideContainers } from './ShowHideContainers.importable';
+import { ShowHideButton } from './ShowHideButton.importable';
import { SignInGateSelector } from './SignInGateSelector.importable';
import { SlotBodyEnd } from './SlotBodyEnd.importable';
import { StickyBottomBanner } from './StickyBottomBanner.importable';
@@ -364,13 +364,9 @@ describe('Island: server-side rendering', () => {
).not.toThrow();
});
- test('ShowHideContainers', () => {
+ test('ShowHideButton', () => {
expect(() =>
- renderToString(
- ,
- ),
+ renderToString(),
).not.toThrow();
});
diff --git a/dotcom-rendering/src/components/Section.tsx b/dotcom-rendering/src/components/Section.tsx
index d9ca350dfdc..fac51a2ab25 100644
--- a/dotcom-rendering/src/components/Section.tsx
+++ b/dotcom-rendering/src/components/Section.tsx
@@ -10,8 +10,9 @@ import { ContainerTitle } from './ContainerTitle';
import { ElementContainer } from './ElementContainer';
import { Flex } from './Flex';
import { Hide } from './Hide';
+import { Island } from './Island';
import { LeftColumn } from './LeftColumn';
-import { ShowHideButton } from './ShowHideButton';
+import { ShowHideButton } from './ShowHideButton.importable';
import { Treats } from './Treats';
/**
@@ -364,7 +365,12 @@ export const Section = ({
/>
{toggleable && !!sectionId && (
-
+
+
+
)}
{toggleable && sectionId ? (
diff --git a/dotcom-rendering/src/components/ShowHideButton.importable.tsx b/dotcom-rendering/src/components/ShowHideButton.importable.tsx
new file mode 100644
index 00000000000..afc70f8f394
--- /dev/null
+++ b/dotcom-rendering/src/components/ShowHideButton.importable.tsx
@@ -0,0 +1,96 @@
+import { css } from '@emotion/react';
+import { isObject, isString, storage } from '@guardian/libs';
+import { space, textSans14 } from '@guardian/source/foundations';
+import { Button } from '@guardian/source/react-components';
+import { useEffect, useState } from 'react';
+import { useIsSignedIn } from '../lib/useAuthStatus';
+import { palette } from '../palette';
+
+type Props = {
+ sectionId: string;
+};
+
+const showHideButtonCss = css`
+ button {
+ ${textSans14};
+ margin-right: 10px;
+ margin-bottom: ${space[2]}px;
+ position: relative;
+ align-items: bottom;
+ text-decoration: none;
+ }
+`;
+
+type ContainerStates = { [id: string]: string };
+
+const isContainerStates = (item: unknown): item is ContainerStates => {
+ if (!isObject(item)) return false;
+ if (!Object.keys(item).every(isString)) return false;
+ if (!Object.values(item).every(isString)) return false;
+ return true;
+};
+
+const getContainerStates = (): ContainerStates => {
+ const item = storage.local.get(`gu.prefs.container-states`);
+ if (!isContainerStates(item)) return {};
+ return item;
+};
+
+/**
+ * Component to toggle the visibility of a front container. Used within FrontSection.
+ **/
+export const ShowHideButton = ({ sectionId }: Props) => {
+ const [containerStates, setContainerStates] = useState({});
+ const [isExpanded, setIsExpanded] = useState(true);
+ const textShowHide = isExpanded ? 'Hide' : 'Show';
+ const isSignedIn = useIsSignedIn();
+
+ const toggleContainer = () => {
+ const section: Element | null =
+ window.document.getElementById(sectionId);
+
+ if (isExpanded) {
+ containerStates[sectionId] = 'closed';
+ section?.classList.add('hidden');
+ } else {
+ containerStates[sectionId] = 'opened';
+ section?.classList.remove('hidden');
+ }
+
+ storage.local.set(`gu.prefs.container-states`, containerStates);
+ };
+
+ useEffect(() => {
+ const section: Element | null =
+ window.document.getElementById(sectionId);
+
+ setContainerStates(getContainerStates());
+
+ const isClosed = containerStates[sectionId] === 'closed';
+ setIsExpanded(!isClosed);
+
+ isClosed
+ ? section?.classList.add('hidden')
+ : section?.classList.remove('hidden');
+ }, [containerStates, sectionId]);
+
+ return (
+ isSignedIn === true && (
+
+
+
+ )
+ );
+};
diff --git a/dotcom-rendering/src/components/ShowHideButton.stories.tsx b/dotcom-rendering/src/components/ShowHideButton.stories.tsx
new file mode 100644
index 00000000000..6dff1d1ebc9
--- /dev/null
+++ b/dotcom-rendering/src/components/ShowHideButton.stories.tsx
@@ -0,0 +1,14 @@
+import type { Meta } from '@storybook/react';
+import { ShowHideButton } from './ShowHideButton.importable';
+
+const meta = {
+ title: 'Components/ShowHideButton',
+ component: ShowHideButton,
+ args: {
+ sectionId: 'sectionId',
+ },
+} satisfies Meta;
+
+export default meta;
+
+export const Default = {};
diff --git a/dotcom-rendering/src/components/ShowHideButton.tsx b/dotcom-rendering/src/components/ShowHideButton.tsx
deleted file mode 100644
index 663cb71de40..00000000000
--- a/dotcom-rendering/src/components/ShowHideButton.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { css } from '@emotion/react';
-import { space, textSans14 } from '@guardian/source/foundations';
-import { ButtonLink } from '@guardian/source/react-components';
-import { palette } from '../palette';
-
-type Props = {
- sectionId: string;
-};
-
-const showHideButtonCss = css`
- ${textSans14};
-
- margin-top: ${space[2]}px;
- margin-right: 10px;
- margin-bottom: ${space[2]}px;
- position: relative;
- align-items: bottom;
- text-decoration: none;
-`;
-
-/**
- * This component creates the styled button for showing & hiding a container,
- * The functionality for this is implemented in a single island 'ShownHideContainers.importable'
- **/
-export const ShowHideButton = ({ sectionId }: Props) => {
- return (
-
- Hide
-
- );
-};
diff --git a/dotcom-rendering/src/components/ShowHideContainers.importable.tsx b/dotcom-rendering/src/components/ShowHideContainers.importable.tsx
deleted file mode 100644
index 7ae4c3ca8b2..00000000000
--- a/dotcom-rendering/src/components/ShowHideContainers.importable.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { isObject, isString, storage } from '@guardian/libs';
-import { useEffect } from 'react';
-
-type ContainerStates = { [id: string]: string };
-
-const isContainerStates = (item: unknown): item is ContainerStates => {
- if (!isObject(item)) return false;
- if (!Object.keys(item).every(isString)) return false;
- if (!Object.values(item).every(isString)) return false;
- return true;
-};
-
-const getContainerStates = (): ContainerStates => {
- const item = storage.local.get(`gu.prefs.container-states`);
-
- if (!isContainerStates(item)) return {};
-
- return item;
-};
-
-type Props = {
- /** When in the ON position, we remove the show/hide functionality for all
- * containers on the page if the user does not have any hidden containers */
- disableFrontContainerToggleSwitch: boolean;
-};
-
-export const ShowHideContainers = ({
- disableFrontContainerToggleSwitch,
-}: Props) => {
- useEffect(() => {
- const containerStates = getContainerStates();
-
- const toggleContainer = (sectionId: string, element: HTMLElement) => {
- const isExpanded = element.getAttribute('aria-expanded') === 'true';
-
- const section: Element | null =
- window.document.getElementById(sectionId);
-
- if (isExpanded) {
- containerStates[sectionId] = 'closed';
- section?.classList.add('hidden');
- element.innerHTML = 'Show';
- element.setAttribute('aria-expanded', 'false');
- element.setAttribute('data-link-name', 'Show');
- } else {
- containerStates[sectionId] = 'opened';
- section?.classList.remove('hidden');
- element.innerHTML = 'Hide';
- element.setAttribute('aria-expanded', 'true');
- element.setAttribute('data-link-name', 'Hide');
- }
-
- storage.local.set(`gu.prefs.container-states`, containerStates);
- };
-
- const allShowHideButtons = Array.from(
- window.document.querySelectorAll(
- '[data-show-hide-button]',
- ),
- );
-
- const allContainersAreExpanded = allShowHideButtons
- .map((el) => {
- const sectionId = el.getAttribute('data-show-hide-button');
- return sectionId && containerStates[sectionId];
- })
- .every((state) => state !== 'closed');
-
- for (const e of allShowHideButtons) {
- // We want to remove the ability to toggle front containers between expanded and collapsed states.
- // The first part of doing this is removing the feature for those who do not currently use it.
- if (disableFrontContainerToggleSwitch && allContainersAreExpanded) {
- e.remove();
- }
-
- const sectionId = e.getAttribute('data-show-hide-button');
- if (!sectionId) continue;
-
- e.onclick = () => toggleContainer(sectionId, e);
-
- if (containerStates[sectionId] === 'closed') {
- toggleContainer(sectionId, e);
- }
- }
- }, [disableFrontContainerToggleSwitch]);
-
- return <>>;
-};