diff --git a/js/api/eclipsefdn.interest-groups.js b/js/api/eclipsefdn.interest-groups.js
index a65b147f697943fd76b44cf93be38fb15c3ba7c5..74bc2c4b938ae10688234e96066a7e37af031868 100644
--- a/js/api/eclipsefdn.interest-groups.js
+++ b/js/api/eclipsefdn.interest-groups.js
@@ -98,3 +98,27 @@ export const getInterestGroupParticipatingOrganizations = async (options) => {
     return [null, error];
   }
 };
+
+/**
+  * Retrieves interest groups that are associated with an organization.
+  *
+  * @param organizationId - The ID of the organization
+  * @returns Interest groups
+  */
+export const getOrganizationInterestGroups = async (organizationId) => {
+  try {
+    const [interestGroups, error] = await getInterestGroups(); 
+    if (error) throw error;
+
+    // Filter interest groups who include any participant or lead that are part
+    // of the organization.
+    const organizationInterestGroups = interestGroups
+      .filter((interestGroup) => [...interestGroup.leads, ...interestGroup.participants]
+        .some((person) => parseInt(person.organization.id) === organizationId)
+      );
+
+    return [organizationInterestGroups, null];
+  } catch (error) {
+    return [null, error];
+  }
+};
diff --git a/js/api/eclipsefdn.working-groups.ts b/js/api/eclipsefdn.working-groups.ts
index d15c35ad9f9510aa8ccf73b4510c2c063da3773f..3a24d351c0e61900d932cd54ecd5cd6be7c10313 100644
--- a/js/api/eclipsefdn.working-groups.ts
+++ b/js/api/eclipsefdn.working-groups.ts
@@ -10,6 +10,8 @@
 
 import 'isomorphic-fetch';
 import { transformSnakeToCamel } from './utils';
+import { WorkingGroup } from '../types/models';
+import { APIResponse, HttpError } from '../types/api';
 
 const apiBasePath = 'https://api.eclipse.org/working-groups';
 
@@ -26,3 +28,27 @@ export const getWorkingGroups = async () => {
   }
 }
 
+/**
+  * Retrieves working groups that are associated with an organization.
+  *
+  * @param organizationId - The ID of the organization
+  * @returns Working groups
+  */
+export const getOrganizationWorkingGroups = async (organizationId: number): Promise<APIResponse<WorkingGroup[]>> => {
+  try {
+    if (!organizationId) {
+      throw new TypeError('No organization id was provided for fetching organization working groups');
+    }
+
+    const response = await fetch(`${apiBasePath}/organization/${organizationId}`);
+    if (!response.ok) throw new HttpError(response.status, `could not fetch working groups for organization ${organizationId}`);
+  
+    const data = await response.json();
+    const workingGroups = data.map(transformSnakeToCamel) as WorkingGroup[];
+
+    return [workingGroups, null];
+  } catch (error) {
+    return [null, error];
+  }
+}
+
diff --git a/js/shared/utils/index.ts b/js/shared/utils/index.ts
index 6f2a8ac617d2e3bf81ed257ef5140e4de5ba1722..4d523fa92cbf27486dddbd39f25a8f28201299b7 100644
--- a/js/shared/utils/index.ts
+++ b/js/shared/utils/index.ts
@@ -8,7 +8,7 @@
  * SPDX-License-Identifier: EPL-2.0
  */
 
-import { WorkingGroup, InterestGroup, Project, ProjectProposal } from '../../types/models';
+import { IndustryCollaboration, WorkingGroup, InterestGroup, Project, ProjectProposal } from '../../types/models';
 
 /**
   * Converts a string to a boolean.
@@ -198,3 +198,27 @@ export const isProjectProposal = (value: object): value is ProjectProposal => {
   );
 };
 
+
+// Strings
+
+/**
+  * Removes non-word characters such as whitespace.
+  * 
+  * @param str - the string to remove non-word characters from 
+  * @returns the same string without non-word characters
+  */
+export const removeNonWordChars = (str: string) => str.replaceAll(/\W/gi, '');
+
+// Comparators
+
+/**
+  * A comparator to sort working groups and interest groups alphabetically by
+  * title.
+  * 
+  * @param a - an industry collaboration
+  * @param b - another industry collaboration to compare against
+  */
+export const industryCollaborationComparator = (a: IndustryCollaboration, b: IndustryCollaboration) => {
+  return removeNonWordChars(a.title).localeCompare(removeNonWordChars(b.title))
+};
+
diff --git a/js/solstice/eclipsefdn.members-detail.js b/js/solstice/eclipsefdn.members-detail.js
index 34a8da6eeb2e42d892bfbc1a8e0668a67ea99737..6f4a36e7523b2e7310590b8cb022f32d240189c4 100644
--- a/js/solstice/eclipsefdn.members-detail.js
+++ b/js/solstice/eclipsefdn.members-detail.js
@@ -12,10 +12,12 @@
  */
 
 import { getOrganizationById, getOrganizationProducts, getOrganizationProjects } from '../api/eclipsefdn.membership';
+import { getOrganizationWorkingGroups } from '../api/eclipsefdn.working-groups';
+import { getOrganizationInterestGroups } from '../api/eclipsefdn.interest-groups';
 import template from './templates/explore-members/member-detail.mustache';
 import { SD_IMG, AP_IMG, AS_IMG } from './eclipsefdn.constants.js';
 import { validateURL } from '../api/utils';
-import { getMonthName } from '../shared/utils';
+import { industryCollaborationComparator, getMonthName } from '../shared/utils';
 
 const render = async () => {
   const element = document.querySelector('.member-detail');
@@ -92,12 +94,16 @@ const render = async () => {
     getOrganizationById(orgId),
     getOrganizationProjects(orgId),
     getOrganizationProducts(orgId),
+    getOrganizationWorkingGroups(orgId),
+    getOrganizationInterestGroups(orgId),
   ];
 
   let responses = await Promise.all(pool);
   const [organization, orgErr] = responses[0];
   const [projects, projectErr] = responses[1];
   const [products, productsErr] = responses[2];
+  const [workingGroups] = responses[3];
+  const [interestGroups] = responses[4];
 
   // Execute the err handler if an error occurred during any request.
   if (orgErr || projectErr || productsErr) {
@@ -109,7 +115,9 @@ const render = async () => {
   const memberDetailData = { 
     ...organization, 
     projects, 
-    products
+    products,
+    workingGroups: workingGroups.sort(industryCollaborationComparator),
+    interestGroups: interestGroups.sort(industryCollaborationComparator),
   };
 
   const getMemberLevelImg = function () {
diff --git a/js/solstice/eclipsefdn.weighted-collaborations.ts b/js/solstice/eclipsefdn.weighted-collaborations.ts
index 67a36562fc79b1b4be554433ed62791fdeb0d944..b5f1147efbdff996384e93e98b172490e7e36362 100644
--- a/js/solstice/eclipsefdn.weighted-collaborations.ts
+++ b/js/solstice/eclipsefdn.weighted-collaborations.ts
@@ -15,7 +15,7 @@ import { getWorkingGroups } from '../api/eclipsefdn.working-groups';
 //@ts-ignore Types do not exist yet
 import { getInterestGroups } from '../api/eclipsefdn.interest-groups';
 import { stringToBoolean, isWorkingGroup, getCollaborationType, repeatSelectUnique } from '../shared/utils';
-import { InterestGroup, WorkingGroup } from '../types/models';
+import { InterestGroup, WorkingGroup, IndustryCollaboration } from '../types/models';
 
 interface Options {
   templateId: string;
@@ -136,9 +136,9 @@ const render = async (): Promise<void> => {
 export default { render };
 
 /** Resolves the website for a given industry collaboration */
-const resolveCollaborationWebsite = (collaboration: WorkingGroup | InterestGroup): string => {
-  if (collaboration.resources.website) {
-    return collaboration.resources.website;
+const resolveCollaborationWebsite = (collaboration: IndustryCollaboration): string => {
+  if (isWorkingGroup(collaboration) && collaboration.resources.website) {
+    return collaboration?.resources.website;
   }
   
   // Use the explore page as a fallback when the collaboration has no
@@ -147,9 +147,9 @@ const resolveCollaborationWebsite = (collaboration: WorkingGroup | InterestGroup
 
   switch (getCollaborationType(collaboration)) {
     case 'working-group':
-      return `${exploreUrl}#wg-${collaboration.alias}`;
+      return `${exploreUrl}#wg-${(collaboration as WorkingGroup).alias}`;
     case 'interest-group':
-      return collaboration.shortProjectId ? `${exploreUrl}#${collaboration.shortProjectId}` : exploreUrl;
+      return (collaboration as InterestGroup).shortProjectId ? `${exploreUrl}#${(collaboration as InterestGroup).shortProjectId}` : exploreUrl;
     default:
       throw new TypeError('Could not resolve website for the given industry collaboration type.');
   }
@@ -203,7 +203,7 @@ const collaborationWeights: Record<string, number> = {
   *
   * @returns The map of weights and buckets with the added collaboration.
   */
-const assignCollaborationToBucket = (weights: Map<number, WorkingGroup | InterestGroup>, collaboration: WorkingGroup | InterestGroup) => {
+const assignCollaborationToBucket = (weights: Map<number, IndustryCollaboration[]>, collaboration: IndustryCollaboration) => {
   // Only working groups have the `alias`.
   let weight: number = isWorkingGroup(collaboration) && collaborationWeights[collaboration.alias];
   
@@ -230,7 +230,7 @@ const assignCollaborationToBucket = (weights: Map<number, WorkingGroup | Interes
   *
   * @returns An industry collaboration.
   */
-const pickRandomCollaborationFromWeights = (buckets: Map<number, WorkingGroup | InterestGroup>): Array<WorkingGroup | InterestGroup> => {
+const pickRandomCollaborationFromWeights = (buckets: Map<number, IndustryCollaboration[]>): IndustryCollaboration => {
   const highestWeight = Array.from(buckets.keys())
     .sort()
     .at(-1);
diff --git a/js/solstice/eclipsefdn.wgs-list.js b/js/solstice/eclipsefdn.wgs-list.js
index 6d149ad65b5a7fd38fca2c0414d09fcaee8a8f32..ab8f1996a30105b052687764bd692c86b76797be 100644
--- a/js/solstice/eclipsefdn.wgs-list.js
+++ b/js/solstice/eclipsefdn.wgs-list.js
@@ -14,6 +14,7 @@
  */
 
 import { displayErrMsg } from './utils';
+import { industryCollaborationComparator } from '../shared/utils';
 import template from './templates/explore-working-groups/working-group-list.mustache';
 import templateLoading from './templates/loading-icon.mustache';
 
@@ -34,8 +35,7 @@ const render = async () => {
     wgsData = wgsData.filter((workingGroup) => workingGroup?.parent_organization !== 'ohwg');
 
     // Remove any non-word characters from title while sorting
-    const removeNonWordChars = wgTitle => wgTitle.replaceAll(/\W/gi, '');
-    wgsData = wgsData.sort((a, b) => removeNonWordChars(a.title).localeCompare(removeNonWordChars(b.title)));
+    wgsData = wgsData.sort(industryCollaborationComparator);
 
   } catch (error) {
     displayErrMsg(element, error);
diff --git a/js/solstice/templates/explore-members/member-detail.mustache b/js/solstice/templates/explore-members/member-detail.mustache
index 604375b6d7de8c5608ae66198035cee2877e02d0..73384c2add547626b33124a7cf9f2bb0e6cc9bad 100644
--- a/js/solstice/templates/explore-members/member-detail.mustache
+++ b/js/solstice/templates/explore-members/member-detail.mustache
@@ -16,6 +16,46 @@
 
     <p>{{{trimDescription}}}</p>
 
+    <hr class="margin-top-60 margin-bottom-40">
+
+    {{#workingGroups.length}}
+      <h2>Working Group Membership</h2>
+      <ul class="member-detail-working-group-list logo-list logo-list-lg margin-top-30 margin-bottom-60">
+        {{#workingGroups}}
+          <li>
+            <a class="link-unstyled flex-center h-100" {{#resources.website}}href="{{resources.website}}"{{/resources.website}}>
+              {{#logo}}
+                <img src="{{logo}}" alt="{{title}}">
+              {{/logo}}
+              {{^logo}}
+                <p class="logo-placeholder-text">{{title}}</p>
+              {{/logo}}
+            </a>
+          </li>
+        {{/workingGroups}}
+      </ul>
+    {{/workingGroups.length}}
+    {{#interestGroups.length}}
+      <h2>Interest Group Membership</h2>
+      <ul class="member-detail-interest-group-list logo-list logo-list-lg margin-top-30 margin-bottom-60">
+        {{#interestGroups}}
+          <li>
+            <a class="link-unstyled flex-center h-100" 
+              {{#resources.website}}href="{{resources.website}}"{{/resources.website}}
+              {{^resources.website}}href="https://projects.eclipse.org/node/{{id}}"{{/resources.website}}
+            >
+              {{#logo}}
+                <img src="{{logo}}" alt="{{title}}">
+              {{/logo}}
+              {{^logo}}
+                <p class="logo-placeholder-text">{{title}}</p>
+              {{/logo}}
+            </a>
+          </li>
+        {{/interestGroups}}
+      </ul>
+    {{/interestGroups.length}}
+
     {{#listings}}
     <h2>{{name}}&apos;s Marketplace Listings</h2>
     <ul>
diff --git a/js/solstice/tests/eclipsefdn.members-detail.test.js b/js/solstice/tests/eclipsefdn.members-detail.test.js
index e570da19c0ee94d11936b7fd4dd21ea289c7b4bd..23212488c741aeae63e685d910091ac2abe9c3d1 100644
--- a/js/solstice/tests/eclipsefdn.members-detail.test.js
+++ b/js/solstice/tests/eclipsefdn.members-detail.test.js
@@ -14,7 +14,11 @@
 
 import eclipsefdnMembersDetail from '../eclipsefdn.members-detail';
 import * as membershipAPIModule from '../../api/eclipsefdn.membership';
+import * as workingGroupsAPIModule from '../../api/eclipsefdn.working-groups';
+import * as interestGroupsAPIModule from '../../api/eclipsefdn.interest-groups';
 import { mockOrganizations, mockOrganizationProducts, mockOrganizationProjects } from '../../api/tests/mocks/membership/mock-data';
+import { mockInterestGroups } from '../../api/tests/mocks/interest-groups/mock-data';
+import { wait } from '../utils';
 
 /*
  * Mutates the search params from `window.location`. This mutates
@@ -40,6 +44,8 @@ const mockSearchParams = (searchParams) => {
 let getOrganizationByIdSpy;
 let getOrganizationProductsSpy;
 let getOrganizationProjectsSpy;
+let getOrganizationWorkingGroupsSpy;
+let getOrganizationInterestGroupsSpy;
 
 const useOrganizationMock = (options) => {
   let organization;
@@ -69,11 +75,24 @@ const useOrganizationMock = (options) => {
     model: mockOrganizationProjects.model[organization.model.organizationId],
   };
 
+  const workingGroups = {
+    api: organization.api.wgpas.map((wgpa) => wgpa.working_group),
+    model: organization.model.wgpas.map((wgpa) => wgpa.workingGroup),
+  }
+
+  // Mutate the interest groups to contain at least one participant from the
+  // organization.
+  let interestGroups = JSON.parse(JSON.stringify(mockInterestGroups)); // Deep copy to prevent mutating the mock data which could be used by other tests.
+  mockInterestGroups.api.forEach((interestGroup) => interestGroup.participants.at(0).organization.id = organization.model.organizationId);
+  mockInterestGroups.model.forEach((interestGroup) => interestGroup.participants.at(0).organization.id = organization.model.organizationId);
+
   getOrganizationByIdSpy.mockImplementation(() => [organization.model, null]);
   getOrganizationProductsSpy.mockImplementation(() => [products.model, null]);
   getOrganizationProjectsSpy.mockImplementation(() => [projects.model, null]);
+  getOrganizationWorkingGroupsSpy.mockImplementation(() => [workingGroups.model, null]);
+  getOrganizationInterestGroupsSpy.mockImplementation(() => [interestGroups.model, null]);
 
-  return { organization, products, projects };
+  return { organization, products, projects, interestGroups };
 }
 
 describe('eclipsefdn-members-detail', () => {
@@ -81,6 +100,8 @@ describe('eclipsefdn-members-detail', () => {
     getOrganizationByIdSpy = jest.spyOn(membershipAPIModule, 'getOrganizationById');
     getOrganizationProductsSpy = jest.spyOn(membershipAPIModule, 'getOrganizationProducts');
     getOrganizationProjectsSpy = jest.spyOn(membershipAPIModule, 'getOrganizationProjects');
+    getOrganizationWorkingGroupsSpy = jest.spyOn(workingGroupsAPIModule, 'getOrganizationWorkingGroups');
+    getOrganizationInterestGroupsSpy = jest.spyOn(interestGroupsAPIModule, 'getOrganizationInterestGroups');
   });
 
   it('Should display error message for missing member_id', async () => {
@@ -155,6 +176,7 @@ describe('eclipsefdn-members-detail', () => {
 
     const params = new URLSearchParams();
     params.set('member_id', organization.model.organizationId);
+
     const cleanup = mockSearchParams(params);
 
     document.body.innerHTML = `
@@ -249,6 +271,66 @@ describe('eclipsefdn-members-detail', () => {
     cleanup();
   });
 
+  it('Should show working groups associated with an organization', async () => {
+    const { organization } = useOrganizationMock();
+
+    const params = new URLSearchParams();
+    params.set('member_id', organization.model.organizationId);
+    const cleanup = mockSearchParams(params);
+
+    document.body.innerHTML = `
+      <div class="member-detail"></div>
+    `;
+
+    await eclipsefdnMembersDetail.render();
+
+    // Create a set of working groups that have been rendered on the page.
+    const workingGroups = new Set(Array
+      .from(document.querySelectorAll('.member-detail-working-group-list img, .member-detail-working-group-list .logo-placeholder-text'))
+      // The alt text would include the working group name.
+      .map((element) => element.getAttribute('alt') ?? element.innerHTML));
+
+    expect(workingGroups.size).not.toBe(0);
+    // Expect every working group within the mock organization to be found in
+      // the set of rendered working groups.
+    expect(
+      organization.api.wgpas
+        .map((wgpa) => wgpa.working_group)
+        .every((workingGroup) => workingGroups.has(workingGroup))
+    )
+
+    cleanup();
+  });
+
+  it('Should show interest groups associated with an organization', async () => {
+    const { organization, interestGroups } = useOrganizationMock();
+
+    const params = new URLSearchParams();
+    params.set('member_id', organization.model.organizationId);
+    const cleanup = mockSearchParams(params);
+
+    document.body.innerHTML = `
+      <div class="member-detail"></div>
+    `;
+
+    await eclipsefdnMembersDetail.render();
+
+    // Create a set of working groups that have been rendered on the page.
+    const renderedInterestGroups = new Set(Array
+      .from(document.querySelectorAll('.member-detail-interest-group-list img, .member-detail-interest-group-list .logo-placeholder-text'))
+      // The alt text would include the working group name.
+      .map((element) => element.getAttribute('alt') ?? element.innerHTML));
+
+    expect(renderedInterestGroups.size).not.toBe(0);
+    // Expect every interest group within the mock organization to be found in
+    // the set of rendered interest groups.
+    expect(
+      interestGroups.model.every((interestGroup) => renderedInterestGroups.has(interestGroup.title))
+    )
+
+    cleanup();
+  });
+
   // it('Should not show links sidebar for organization without products or projects', () => {});
   // it('Should display formatted member since date', () => {});
   // it('Should render long description without line breaks', () => {});
diff --git a/js/solstice/utils/index.ts b/js/solstice/utils/index.ts
index 70ade3b11b5133dbcd44348255ec60cb2ba91efd..5a8a3a7c2820c7229383a98b182ba69889d5a26d 100644
--- a/js/solstice/utils/index.ts
+++ b/js/solstice/utils/index.ts
@@ -84,4 +84,3 @@ export const waitForRender = (element: HTMLElement | Node): Promise<void> => {
     observer.observe(element, { childList: true });
   });
 };
-
diff --git a/js/types/models.ts b/js/types/models.ts
index a0286287e517b28c15645015c28fb25b45154ce9..f9dadf35fc3558f9322aa6be87d369cca64cbe91 100644
--- a/js/types/models.ts
+++ b/js/types/models.ts
@@ -115,11 +115,48 @@ export interface OrganizationProduct {
   url: string;
 }
 
-//== Working Group Models
-export type WorkingGroup = any;
+//== Industry Collaboration Models
+export interface WorkingGroupRelationLevels {
+  relation: string;
+  description: string;
+}
+export interface WorkingGroup {
+  alias: string;
+  title: string;
+  status: 'active' | 'inactive' | 'proposal';
+  logo?: string;
+  description?: string;
+  parentOrganization: string;
+  resources: {
+    charter: string;
+    website: string;
+    members: string;
+    sponsorship: string;
+    contactForm: string;
+    participationAgreements: {
+      individual?: unknown;
+      organization: {
+        pdf: string;
+        documentId: string;
+      }
+    }
+  },
+  levels: WorkingGroupRelationLevels[];
+};
+
+export interface InterestGroup {
+  shortProjectId: string;
+  title: string;
+  state: 'active';
+  description: {
+    summary: string;
+    full: string;
+  },
+  logo: string;
+};
+
+export type IndustryCollaboration = WorkingGroup | InterestGroup;
 
-//== Project Models
-export type InterestGroup = any;
 //== Project Models
 
 export interface PMIUser {
diff --git a/less/astro/components/_lists.less b/less/astro/components/_lists.less
new file mode 100644
index 0000000000000000000000000000000000000000..33780cdf4a80bba367713a71310a826778469e2c
--- /dev/null
+++ b/less/astro/components/_lists.less
@@ -0,0 +1,43 @@
+/*!
+ * Copyright (c) 2025 Eclipse Foundation, Inc.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+*/
+
+.logo-list {
+  .list-unstyled;
+  display: flex;
+  gap: 2rem;
+  flex-wrap: wrap;
+  text-align: center;
+
+  li {
+    max-width: 11rem;
+    height: 8rem;
+  }
+
+  img {
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
+  }
+
+  &-lg {
+    gap: 4rem;
+
+    li {
+      max-width: 20rem;
+      height: 8rem;
+    }
+  }
+
+  .logo-placeholder-text {
+    font-size: @logo-placeholder-text-font-size;
+    font-weight: @logo-placeholder-text-font-weight;
+  }
+}
+
diff --git a/less/astro/main.less b/less/astro/main.less
index 4ffe547913c467a71eb8853405d6cf1c378abb2d..44599b689ba668089938883fe15521cbd87e3afc 100644
--- a/less/astro/main.less
+++ b/less/astro/main.less
@@ -96,6 +96,7 @@
 @import 'components/_feed-list.less';
 @import 'components/_timeline.less';
 @import 'components/_header-nav.less';
+@import 'components/_lists.less';
 @import 'components/_news-list.less';
 @import 'components/_project-list.less';
 @import 'components/_resources-group.less';
diff --git a/tsconfig.json b/tsconfig.json
index 6171fbeac0edad5a7aabcae5d318de2880bf1cb0..4b7933149fcde01e11da24342faff20f47098147 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,6 +6,7 @@
     "noImplicitAny": true,
     "sourceMap": true,
     "allowSyntheticDefaultImports": true,
+    "lib": ["ES2022"],
   },
   "include": ["js/**/*"]
 }