Repository: carbon-design-system/carbon-labs
Pull request #559: chore(animated-header): Expose selectedDropdown items renderers
Author: login: IronZDev
Created: 2025-04-08T09:17:09Z | Merged: 2025-04-09T15:27:22Z

PR to expose `renderSelectedItem` props of Workspace/TileGroup dropdowns.

#### Changelog

**New**

- exposed `renderHeaderSelectedItem` and `renderWorkspaceSelectedItem` props for main Header dropdown and workspace dropdown consecutively.

**Changed**

- made `handleHeaderItemsToString` and `handleWorkspaceItemsToString` optional



Diff:
diff --git a/examples/react/AnimatedHeader/src/App.tsx b/examples/react/AnimatedHeader/src/App.tsx
index a3b7f3da9..036d40050 100644
--- a/examples/react/AnimatedHeader/src/App.tsx
+++ b/examples/react/AnimatedHeader/src/App.tsx
@@ -14,6 +14,10 @@ import {
   watsonXStaticLight,
 } from '@carbon-labs/react-animated-header/assets';
 import { headerTiles, workspaceData, tasksConfigDropdown } from './data';
+import {
+  SelectedWorkspace,
+  TileGroup,
+} from '@carbon-labs/react-animated-header/es/components/AnimatedHeader/AnimatedHeader';
 
 function App() {
   const [tiles] = useState(headerTiles);
@@ -29,13 +33,16 @@ function App() {
     setSelectedTile(e.selectedItem.id);
   };
 
-  const handleHeaderItems = (item: any) => {
-    return item ? item.label : '';
-  };
+  const handleHeaderItems = (item: TileGroup | null) => item?.label ?? '';
 
-  const handleWorkspaceItems = (item: any) => {
-    return item ? item.label : '';
-  };
+  const handleWorkspaceItems = (item: SelectedWorkspace | null) =>
+    item?.label ?? '';
+
+  const selectedWorkspaceItemRenderer = (item: SelectedWorkspace | null) =>
+    item?.label ?? '';
+
+  const selectedTileGroupRenderer = (item: TileGroup | null) =>
+    item?.label ?? '';
 
   return (
     <AnimatedHeader
@@ -47,6 +54,8 @@ function App() {
       headerAnimation={watsonXAnimatedLight}
       headerStatic={watsonXStaticLight}
       productName="[Product name]"
+      renderHeaderSelectedItem={selectedTileGroupRenderer}
+      renderWorkspaceSelectedItem={selectedWorkspaceItemRenderer}
       selectedTileGroup={selectedTile}
       selectedWorkspace={selectedWorkspace}
       setSelectedTileGroup={handleTileGroup}
diff --git a/packages/react/src/components/AnimatedHeader/__stories__/AnimatedHeader.mdx b/packages/react/src/components/AnimatedHeader/__stories__/AnimatedHeader.mdx
index 873e3ec72..de0218ff2 100644
--- a/packages/react/src/components/AnimatedHeader/__stories__/AnimatedHeader.mdx
+++ b/packages/react/src/components/AnimatedHeader/__stories__/AnimatedHeader.mdx
@@ -143,6 +143,8 @@ Example of Animated Header with all prop types enabled.
   headerAnimation={watsonXAnimatedLight}
   headerStatic={watsonXStaticLight}
   productName="[Product name]"
+  renderHeaderSelectedItem={tileGroupSelectedItemRenderer}
+  renderWorkspaceSelectedItem={workspaceSelectedItemRenderer}
   selectedTileGroup={selectedTile}
   selectedWorkspace={selectedWorkspace}
   setSelectedTileGroup={handleTileGroup}
diff --git a/packages/react/src/components/AnimatedHeader/components/AnimatedHeader/AnimatedHeader.tsx b/packages/react/src/components/AnimatedHeader/components/AnimatedHeader/AnimatedHeader.tsx
index ab0942b24..48663139f 100644
--- a/packages/react/src/components/AnimatedHeader/components/AnimatedHeader/AnimatedHeader.tsx
+++ b/packages/react/src/components/AnimatedHeader/components/AnimatedHeader/AnimatedHeader.tsx
@@ -7,7 +7,7 @@
  * LICENSE file in the root directory of this source tree.
  */
 import PropTypes from 'prop-types';
-import React, { useEffect, useRef, useState } from 'react';
+import React, { ReactNode, useEffect, useRef, useState } from 'react';
 import {
   Grid,
   Column,
@@ -61,8 +61,10 @@ export interface AnimatedHeaderProps {
   allTiles: TileGroup[];
   allWorkspaces?: SelectedWorkspace[];
   description?: string;
-  handleHeaderItemsToString: (item: TileGroup | null) => string;
-  handleWorkspaceItemsToString: (item: SelectedWorkspace | null) => string;
+  handleHeaderItemsToString?: (item: TileGroup | null) => string;
+  renderHeaderSelectedItem?: (item: TileGroup | null) => ReactNode;
+  handleWorkspaceItemsToString?: (item: SelectedWorkspace | null) => string;
+  renderWorkspaceSelectedItem?: (item: SelectedWorkspace | null) => ReactNode;
   headerAnimation?: object;
   headerStatic?: React.JSX.Element;
   productName?: string;
@@ -85,6 +87,8 @@ const AnimatedHeader: React.FC<AnimatedHeaderProps> = ({
   headerAnimation,
   headerStatic,
   productName = '[Product name]',
+  renderHeaderSelectedItem,
+  renderWorkspaceSelectedItem,
   selectedTileGroup,
   selectedWorkspace,
   setSelectedTileGroup,
@@ -238,8 +242,13 @@ const AnimatedHeader: React.FC<AnimatedHeaderProps> = ({
                     hideLabel
                     type="inline"
                     items={allTiles}
-                    itemToString={(item) => handleHeaderItemsToString(item)}
                     onChange={(e) => setSelectedTileGroup(e)}
+                    {...(handleHeaderItemsToString
+                      ? { itemToString: handleHeaderItemsToString }
+                      : {})}
+                    {...(renderHeaderSelectedItem
+                      ? { renderSelectedItem: renderHeaderSelectedItem }
+                      : {})}
                   />
                 </div>
               )}
@@ -262,8 +271,13 @@ const AnimatedHeader: React.FC<AnimatedHeaderProps> = ({
                   hideLabel
                   type="inline"
                   items={allWorkspaces}
-                  itemToString={(item) => handleWorkspaceItemsToString(item)}
                   onChange={(e) => setSelectedWorkspace(e)}
+                  {...(handleWorkspaceItemsToString
+                    ? { itemToString: handleWorkspaceItemsToString }
+                    : {})}
+                  {...(renderWorkspaceSelectedItem
+                    ? { renderSelectedItem: renderWorkspaceSelectedItem }
+                    : {})}
                 />
               </div>
             )}
@@ -357,6 +371,20 @@ const AnimatedHeader: React.FC<AnimatedHeaderProps> = ({
    */
   productName: PropTypes.string,
 
+  /**
+   * Helper function passed to downshift that allows the library to render a
+   * selected item to as an arbitrary ReactNode. By default it uses standard Carbon renderer that renders only item.label text
+   * (Dropdown under description in header)
+   */
+  renderHeaderSelectedItem: PropTypes.func,
+
+  /**
+   * Helper function passed to downshift that allows the library to render a
+   * selected item to as an arbitrary ReactNode. By default it uses standard Carbon renderer that renders only item.label text
+   * (Dropdown related to workspace selection)
+   */
+  renderWorkspaceSelectedItem: PropTypes.func,
+
   /**
    * The tile group that is active in the header
    * ex. "AI Chat Tile w/ two glass tiles", "Four glass tiles", ect.


Reviews:
user: login: glapadre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T19:31:37Z
user: login: glapadre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T19:32:11Z
user: login: glapadre
body: Add `renderHeaderSelectedItem={selectedTileGroupRenderer}` and `renderWorkspaceSelectedItem={selectedWorkspaceItemRenderer}` to `AnimatedHeader.mdx: (line 146:0)` as well. Otherwise LGTM
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T19:34:47Z
user: login: glapadre
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T14:19:27Z

Review comments:
diff_hunk: @@ -44,6 +51,8 @@ function App() {
       description="Connect, monitor, and manage data."
       handleHeaderItemsToString={handleHeaderItems}
       handleWorkspaceItemsToString={handleWorkspaceItems}
+      renderHeaderSelectedItem={selectedTileGroupRenderer}
+      renderWorkspaceSelectedItem={selectedWorkspaceItemRenderer}
path: examples/react/AnimatedHeader/src/App.tsx
user: login: glapadre
body: Not required but I have been ordering the props alphabetically 
created_at: 2025-04-08T19:31:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -61,8 +61,10 @@ export interface AnimatedHeaderProps {
   allTiles: TileGroup[];
   allWorkspaces?: SelectedWorkspace[];
   description?: string;
-  handleHeaderItemsToString: (item: TileGroup | null) => string;
-  handleWorkspaceItemsToString: (item: SelectedWorkspace | null) => string;
+  handleHeaderItemsToString?: (item: TileGroup | null) => string;
+  renderHeaderSelectedItem?: (item: TileGroup | null) => ReactNode;
path: packages/react/src/components/AnimatedHeader/components/AnimatedHeader/AnimatedHeader.tsx
user: login: glapadre
body: Same thing here alphabetical order 
created_at: 2025-04-08T19:32:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: netlify[bot]
created_at: 2025-04-08T09:17:26Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *carbon-labs-react* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 76ca15c803195f638b2c5d009827a23f3f59e222 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/carbon-labs-react/deploys/67f4e998a592fd000825cded |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-559--carbon-labs-react.netlify.app](https://deploy-preview-559--carbon-labs-react.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTU1OS0tY2FyYm9uLWxhYnMtcmVhY3QubmV0bGlmeS5hcHAifQ.0inw_rlECsjRrYG0UULMAQQM6Rpx6Ox3aiySYjWzzJY)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [carbon-labs-react Preview](https://deploy-preview-559--carbon-labs-react.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/carbon-labs-react/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: netlify[bot]
created_at: 2025-04-08T09:17:27Z
body: ### <span aria-hidden="true">❌</span> Deploy Preview for *carbon-labs-web-components* failed. **[Why did it fail? →](https://app.netlify.com/sites/carbon-labs-web-components/deploys/67f4e997e345df0008235707?deploy_diagnostics=true)**


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 76ca15c803195f638b2c5d009827a23f3f59e222 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/carbon-labs-web-components/deploys/67f4e997e345df0008235707 |
author_association: NONE
user: login: netlify[bot]
created_at: 2025-04-08T09:19:20Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *carbon-labs-react* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | c4a1fb7af22bef2f4414ae44bffbc373e072505d |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/carbon-labs-react/deploys/67f61faa54070f0008508c47 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-559--carbon-labs-react.netlify.app](https://deploy-preview-559--carbon-labs-react.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTU1OS0tY2FyYm9uLWxhYnMtcmVhY3QubmV0bGlmeS5hcHAifQ.0inw_rlECsjRrYG0UULMAQQM6Rpx6Ox3aiySYjWzzJY)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [carbon-labs-react Preview](https://deploy-preview-559--carbon-labs-react.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/carbon-labs-react/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: netlify[bot]
created_at: 2025-04-08T09:21:05Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *carbon-labs-web-components* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | c4a1fb7af22bef2f4414ae44bffbc373e072505d |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/carbon-labs-web-components/deploys/67f61faac8225e0008fb35f8 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-559--carbon-labs-web-components.netlify.app](https://deploy-preview-559--carbon-labs-web-components.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTU1OS0tY2FyYm9uLWxhYnMtd2ViLWNvbXBvbmVudHMubmV0bGlmeS5hcHAifQ.do_J4T4QdLe4Npwn2Mero_LE9yaAnEezBJc8mV8ZuGY)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [carbon-labs-web-components Preview](https://deploy-preview-559--carbon-labs-web-components.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/carbon-labs-web-components/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: IronZDev
created_at: 2025-04-09T07:19:45Z
body: @glapadre all done!
author_association: CONTRIBUTOR