Repository: cengage/react-magma
Pull request #1729: feat(Popover): Add functionality to use `Esc` button, fix docs, add `maxWidth` to content
Author: login: nikitaorliak-cengage
Labels: name: needs design feedback
description: Waiting for Design approval or feedback
Created: 2025-04-01T11:52:59Z | Merged: 2025-04-04T14:42:46Z

Closes: #927

## What I did
<!--
Include description of the change and type of change:
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- Documentation change (docs or storybook only)
- Other: style, refactor, performance, build, chore
-->
Fix comments: add functionality to use `Esc` button everywhere, fix docs, add `maxWidth` to content.

## Screenshots
<!-- Include screenshot of your change, when applicable -->

## Checklist 
- [x] changeset has been added
- [x] Pull request is assigned, labels have been added and ticket is linked
- [x] Pull request description is descriptive and testing steps are listed
- [ ] Corresponding changes to the documentation have been made
- [x] New and existing unit tests pass locally with the proposed changes
- [ ] Tests that prove the fix is effective or that the feature works have been added

## How to test
<!-- Include testing steps, list of edge cases, components affected by this change, etc. -->
Open Popover -> Check that everything works as expected.


Diff:
diff --git a/.changeset/feat-popover-fix-comments.md b/.changeset/feat-popover-fix-comments.md
new file mode 100644
index 0000000000..9ac5317531
--- /dev/null
+++ b/.changeset/feat-popover-fix-comments.md
@@ -0,0 +1,5 @@
+---
+'react-magma-dom': minor
+---
+
+feat(Popover): Fix comments: add functionality to use `Esc` button everywhere, fix docs, add `maxWidth` to content.
diff --git a/packages/react-magma-dom/src/components/InputBase/index.tsx b/packages/react-magma-dom/src/components/InputBase/index.tsx
index 279fe3ad0b..a54d9c2241 100644
--- a/packages/react-magma-dom/src/components/InputBase/index.tsx
+++ b/packages/react-magma-dom/src/components/InputBase/index.tsx
@@ -14,6 +14,7 @@ import { useForkedRef } from '../../utils';
 import { ButtonShape, ButtonSize, ButtonType, ButtonVariant } from '../Button';
 import { IconButton } from '../IconButton';
 import { LabelPosition } from '../Label';
+import { ChildrenWrapper } from '../StyledButton';
 
 export enum InputSize {
   large = 'large',
@@ -615,7 +616,7 @@ export const HelpLinkContainer = styled.span<{
         ? '0'
         : `calc(-100% - ${props.theme.spaceScale.spacing03})`}
   );
-  svg {
+  ${ChildrenWrapper} > svg {
     height: ${props => getHelpLinkSVGSize(props)};
     width: ${props => getHelpLinkSVGSize(props)};
   }
diff --git a/packages/react-magma-dom/src/components/Popover/Popover.stories.tsx b/packages/react-magma-dom/src/components/Popover/Popover.stories.tsx
index 7429319137..6286583e50 100644
--- a/packages/react-magma-dom/src/components/Popover/Popover.stories.tsx
+++ b/packages/react-magma-dom/src/components/Popover/Popover.stories.tsx
@@ -587,7 +587,7 @@ const InputExampleTemplate = args => {
             width="320px"
           />
         </PopoverTrigger>
-        <PopoverContent>
+        <PopoverContent style={{ maxWidth: '100%' }}>
           <div
             style={{
               display: 'flex',
diff --git a/packages/react-magma-dom/src/components/Popover/Popover.tsx b/packages/react-magma-dom/src/components/Popover/Popover.tsx
index 90ae8a22f7..b87e4d0094 100644
--- a/packages/react-magma-dom/src/components/Popover/Popover.tsx
+++ b/packages/react-magma-dom/src/components/Popover/Popover.tsx
@@ -193,6 +193,20 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(
       }
     }, []);
 
+    React.useEffect(() => {
+      const handleEsc = event => {
+        if (event.key === 'Escape' && isOpen) {
+          closePopover(event);
+        }
+      };
+
+      window.addEventListener('keydown', handleEsc);
+
+      return () => {
+        window.removeEventListener('keydown', handleEsc);
+      };
+    }, [isOpen]);
+
     const popoverId = useGenerateId(defaultId);
 
     popoverTriggerId.current = `${popoverId}_trigger`;
@@ -235,7 +249,7 @@ export const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(
     }
 
     function handleKeyDown(event: React.KeyboardEvent) {
-      if (event.key === 'Escape' && event.target !== toggleRef.current) {
+      if (event.key === 'Escape') {
         event.nativeEvent.stopImmediatePropagation();
         closePopover(event);
       }
diff --git a/packages/react-magma-dom/src/components/Popover/PopoverContent.tsx b/packages/react-magma-dom/src/components/Popover/PopoverContent.tsx
index ca4eda00d9..8c15646f1d 100644
--- a/packages/react-magma-dom/src/components/Popover/PopoverContent.tsx
+++ b/packages/react-magma-dom/src/components/Popover/PopoverContent.tsx
@@ -54,6 +54,7 @@ const StyledCard = styled(Card)<{
         ? props.theme.colors.primary400
         : props.theme.colors.neutral300};
   width: ${props => (props.width ? props.width : '100%')};
+  max-width: 300px;
 `;
 
 const StyledAnnounce = styled(Announce)`
diff --git a/packages/react-magma-dom/src/components/Popover/__snapshots__/Popover.test.js.snap b/packages/react-magma-dom/src/components/Popover/__snapshots__/Popover.test.js.snap
index 8d6a1da7e2..dfd213f06a 100644
--- a/packages/react-magma-dom/src/components/Popover/__snapshots__/Popover.test.js.snap
+++ b/packages/react-magma-dom/src/components/Popover/__snapshots__/Popover.test.js.snap
@@ -31,6 +31,7 @@ exports[`Popover should render the popover with isInverse prop 1`] = `
   white-space: nowrap;
   border: 1px solid #5D65CB;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -88,6 +89,7 @@ exports[`Popover should render the popover with isInverse prop 1`] = `
   white-space: nowrap;
   border: 1px solid #5D65CB;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -176,6 +178,7 @@ exports[`Popover should render the popover with pointer by default 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -233,6 +236,7 @@ exports[`Popover should render the popover with pointer by default 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -321,6 +325,7 @@ exports[`Popover should render the popover with target width 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 0px;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -378,6 +383,7 @@ exports[`Popover should render the popover with target width 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 0px;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -466,6 +472,7 @@ exports[`Popover should render the popover without pointer 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
@@ -523,6 +530,7 @@ exports[`Popover should render the popover without pointer 1`] = `
   white-space: nowrap;
   border: 1px solid #D4D4D4;
   width: 100%;
+  max-width: 300px;
 }
 
 .emotion-3 {
diff --git a/packages/react-magma-dom/src/components/StyledButton/index.tsx b/packages/react-magma-dom/src/components/StyledButton/index.tsx
index 1e469d8d5e..dfb8906fc5 100644
--- a/packages/react-magma-dom/src/components/StyledButton/index.tsx
+++ b/packages/react-magma-dom/src/components/StyledButton/index.tsx
@@ -120,7 +120,10 @@ const SpinnerWrapper = styled.span`
   display: flex;
 `;
 
-const ChildrenWrapper = styled.span<{ isLoading: boolean; testId?: string }>`
+export const ChildrenWrapper = styled.span<{
+  isLoading: boolean;
+  testId?: string;
+}>`
   visibility: ${props => (props.isLoading ? 'hidden' : 'visible')};
   display: inline-flex;
   align-items: center;
diff --git a/website/react-magma-docs/src/pages/api/popover.mdx b/website/react-magma-docs/src/pages/api/popover.mdx
index cd1d64d2db..23c48b853d 100644
--- a/website/react-magma-docs/src/pages/api/popover.mdx
+++ b/website/react-magma-docs/src/pages/api/popover.mdx
@@ -28,6 +28,7 @@ The `Popover` component is composed of two main parts: the trigger element (prov
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -60,6 +61,7 @@ By setting the `hoverable` prop to true, the popover will remain open while the
 
 ```tsx
 import React from 'react';
+
 import { Popover, PopoverTrigger, PopoverContent } from 'react-magma-dom';
 
 export function Example() {
@@ -80,6 +82,7 @@ The `hasPointer` prop controls the display of an arrow pointer that visually con
 
 ```tsx
 import React from 'react';
+
 import { Popover, PopoverTrigger, PopoverContent } from 'react-magma-dom';
 
 export function Example() {
@@ -102,6 +105,7 @@ You can programmatically control the popover by providing an `apiRef`. The Popov
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -141,6 +145,7 @@ When the `focusTrap` prop is enabled, keyboard focus is trapped within the popov
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -173,7 +178,7 @@ export function Example() {
         <FormGroup>
           <Toggle
             labelText="Setting 1"
-            defaultChecked={true}
+            defaultChecked
             containerStyle={{
               width: '100%',
               justifyContent: 'space-between',
@@ -203,10 +208,11 @@ export function Example() {
 
 ## Custom Width and Max Height
 
-Customize the size of your popover using the `width` and `maxHeight` props. You can provide these values as strings (with units) or as numbers (interpreted as pixels). Using `width=“taget”` will set the width of the content based on the width of the trigger.
+Customize the size of your popover using the `width` and `maxHeight` props. You can provide these values as strings (with units) or as numbers (interpreted as pixels). Using `width=“target”` will set the width of the content based on the width of the trigger.
 
 ```tsx
 import React from 'react';
+
 import { Popover, PopoverTrigger, PopoverContent } from 'react-magma-dom';
 
 export function Example() {
@@ -229,6 +235,7 @@ The `position` prop sets the default position for the popover in relation to its
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -266,6 +273,7 @@ To structure the content of your popover, use the `PopoverHeader` and `PopoverFo
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -300,6 +308,7 @@ The `PopoverTrigger` component supports both icon-only and text-based triggers.
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -337,6 +346,7 @@ The `isDisabled` property will disable the ability to open the popover. For disa
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -376,6 +386,7 @@ The `openByDefault` property will allow Popover to open as soon as the page load
 
 ```tsx
 import React from 'react';
+
 import {
   Popover,
   PopoverTrigger,
@@ -443,6 +454,45 @@ export function Example() {
 }
 ```
 
+## Inverse
+
+The `isInverse` property is an optional boolean, that reverses the colors so that the component can better appear on a dark background. The default value is `false`.
+
+```tsx
+import React from 'react';
+
+import {
+  Card,
+  CardBody,
+  Popover,
+  PopoverTrigger,
+  PopoverContent,
+  PopoverHeader,
+  PopoverFooter,
+} from 'react-magma-dom';
+
+export function Example() {
+  return (
+    <Card isInverse>
+      <CardBody>
+        <Popover isInverse>
+          <PopoverTrigger>Click me</PopoverTrigger>
+          <PopoverContent>
+            <PopoverHeader>
+              <div>Popover Title</div>
+            </PopoverHeader>
+            <div>This is the main content of the popover</div>
+            <PopoverFooter>
+              <div>Footer Content</div>
+            </PopoverFooter>
+          </PopoverContent>
+        </Popover>
+      </CardBody>
+    </Card>
+  );
+}
+```
+
 ## Popover Props
 
 **Any additional props supplied will be provided to the wrapping div element.**


Reviews:
user: login: olehnoskov-cengage
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-01T14:00:39Z
user: login: nikitaorliak-cengage
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-02T08:50:18Z
user: login: olehnoskov-cengage
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-02T09:52:29Z
user: login: moathabuhamad-cengage
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-02T13:01:48Z
user: login: silvalaura
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-02T13:40:42Z
user: login: silvalaura
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-03T13:42:59Z

Review comments:
diff_hunk: @@ -54,12 +55,52 @@ export function Example() {
 }
 ```
 
+##Inverse
path: website/react-magma-docs/src/pages/api/popover.mdx
user: login: olehnoskov-cengage
body: Please add space between ## and Inverse.
![Screenshot from 2025-04-01 16-54-53](https://github.com/user-attachments/assets/a065bf98-e961-4005-ac84-cb8362f7f11e)

created_at: 2025-04-01T13:55:13Z
author_association: COLLABORATOR
diff_hunk: @@ -54,12 +55,52 @@ export function Example() {
 }
 ```
 
+##Inverse
path: website/react-magma-docs/src/pages/api/popover.mdx
user: login: nikitaorliak-cengage
body: Fixed
created_at: 2025-04-02T08:50:18Z
author_association: COLLABORATOR
diff_hunk: @@ -54,12 +55,52 @@ export function Example() {
 }
 ```
 
+## Inverse
path: website/react-magma-docs/src/pages/api/popover.mdx
user: login: silvalaura
body: Sorry to nitpick, but the inverse example is towards the end of almost every other component. Could we move it down to be the last example?
created_at: 2025-04-02T13:38:19Z
author_association: COLLABORATOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-04-01T11:53:03Z
body: ###  🦋  Changeset detected

Latest commit: 60fecf8ad0d9d182f23aa4cdd01a48ca3dc0395c

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name            | Type  |
| --------------- | ----- |
| react-magma-dom | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/cengage/react-magma/new/feat/popover-fix-comments?filename=.changeset/few-plants-switch.md&value=---%0A%22react-magma-docs%22%3A%20patch%0A%22react-magma-dom%22%3A%20patch%0A---%0A%0Afeat(Popover)%3A%20Add%20functionality%20to%20use%20%60Esc%60%20button%2C%20fix%20docs%2C%20add%20%60maxWidth%60%20to%20content%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-01T12:03:35Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://docs-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-01T12:03:40Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://storybook-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR
user: login: moathabuhamad-cengage
created_at: 2025-04-01T12:12:49Z
body: * In input and profile examples, tabbing into the component with the keyboard doesn't open the popover, is there a way to open it without a mouse click? 
* is there a unique expected behavior intended in the `don't show again` example? Because I can still open it even if don't show again is marked.
author_association: COLLABORATOR
user: login: nikitaorliak-cengage
created_at: 2025-04-02T08:48:55Z
body: > * In input and profile examples, tabbing into the component with the keyboard doesn't open the popover, is there a way to open it without a mouse click?

Devs can use the `isHoverable` prop if they want to open popover in writable elements such as `Input`.

> * is there a unique expected behavior intended in the `don't show again` example? Because I can still open it even if don't show again is marked.

Yes, this prop allows you to open the Popover immediately after the page loads. The `Don't show again` checkbox prevents this behavior.
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-04-02T08:59:09Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://docs-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-02T08:59:14Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://storybook-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-03T10:09:08Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://docs-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-03T10:09:13Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://storybook-preview-1729--upbeat-sinoussi-f675aa.netlify.app
author_association: CONTRIBUTOR