diff --git a/.loki/reference/chrome_desktop_Forms_EuiSelectable_Playground.png b/.loki/reference/chrome_desktop_Forms_EuiSelectable_Playground.png
new file mode 100644
index 00000000000..a56a1d996f8
Binary files /dev/null and b/.loki/reference/chrome_desktop_Forms_EuiSelectable_Playground.png differ
diff --git a/.loki/reference/chrome_desktop_Forms_EuiSelectable_With_Tooltip.png b/.loki/reference/chrome_desktop_Forms_EuiSelectable_With_Tooltip.png
new file mode 100644
index 00000000000..a56a1d996f8
Binary files /dev/null and b/.loki/reference/chrome_desktop_Forms_EuiSelectable_With_Tooltip.png differ
diff --git a/.loki/reference/chrome_mobile_Forms_EuiSelectable_Playground.png b/.loki/reference/chrome_mobile_Forms_EuiSelectable_Playground.png
new file mode 100644
index 00000000000..7fac77a3b49
Binary files /dev/null and b/.loki/reference/chrome_mobile_Forms_EuiSelectable_Playground.png differ
diff --git a/.loki/reference/chrome_mobile_Forms_EuiSelectable_With_Tooltip.png b/.loki/reference/chrome_mobile_Forms_EuiSelectable_With_Tooltip.png
new file mode 100644
index 00000000000..7fac77a3b49
Binary files /dev/null and b/.loki/reference/chrome_mobile_Forms_EuiSelectable_With_Tooltip.png differ
diff --git a/changelogs/upcoming/7715.md b/changelogs/upcoming/7715.md
new file mode 100644
index 00000000000..f4b60264dfb
--- /dev/null
+++ b/changelogs/upcoming/7715.md
@@ -0,0 +1,6 @@
+- Added support for `toolTipContent` and `toolTipProps` props on `EuiSelectable` options
+
+**Bug fixes**
+
+- Fixed issue with unmounted component state updates on requestAnimationFrame for `EuiSelectable`
+
diff --git a/src-docs/src/views/selectable/selectable_example.js b/src-docs/src/views/selectable/selectable_example.js
index 301af959245..027f37ba7fe 100644
--- a/src-docs/src/views/selectable/selectable_example.js
+++ b/src-docs/src/views/selectable/selectable_example.js
@@ -9,6 +9,7 @@ import {
EuiSelectableMessage,
EuiText,
EuiTextTruncate,
+ EuiToolTip,
EuiCallOut,
EuiLink,
} from '../../../../src';
@@ -42,6 +43,9 @@ const selectableSizingSource = require('!!raw-loader!./selectable_sizing');
import Truncation from './selectable_truncation';
const truncationSource = require('!!raw-loader!./selectable_truncation');
+import SelectableToolTips from './selectable_tool_tips';
+const selectableToolTipsSource = require('!!raw-loader!./selectable_tool_tips');
+
import SelectableCustomRender from './selectable_custom_render';
const selectableCustomRenderSource = require('!!raw-loader!./selectable_custom_render');
@@ -439,6 +443,57 @@ export const SelectableExample = {
`,
demo: ,
},
+
+ {
+ title: 'Tooltips',
+ source: [
+ {
+ type: GuideSectionTypes.TSX,
+ code: selectableToolTipsSource,
+ },
+ ],
+ text: (
+ <>
+
+ If you have longer information that you need to make available to
+ users outside of truncated text, one approach could be adding
+ tooltip descriptions to individual options by passing{' '}
+ toolTipContent.
+
+
+ You can additionally customize individual tooltip behavior by
+ passing toolTipProps, which accepts any
+ configuration that{' '}
+
+ EuiToolTip
+ {' '}
+ accepts.
+
+ >
+ ),
+ props: {
+ EuiSelectableOptionProps,
+ EuiToolTip,
+ },
+ demo: ,
+ snippet: ` setOptions(newOptions)}
+>
+ {list => list}
+`,
+ },
{
title: 'Rendering the options',
source: [
diff --git a/src-docs/src/views/selectable/selectable_tool_tips.tsx b/src-docs/src/views/selectable/selectable_tool_tips.tsx
new file mode 100644
index 00000000000..2536041f47e
--- /dev/null
+++ b/src-docs/src/views/selectable/selectable_tool_tips.tsx
@@ -0,0 +1,34 @@
+import React, { useState } from 'react';
+
+import { EuiSelectable, EuiSelectableOption } from '../../../../src';
+
+export default () => {
+ const [options, setOptions] = useState([
+ {
+ label: 'Titan',
+ toolTipContent:
+ 'Titan is the largest moon of Saturn and the second-largest in the Solar System',
+ },
+ {
+ label: 'Pandora',
+ toolTipContent:
+ "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
+ },
+ {
+ label: 'Iapetus',
+ toolTipContent: "Iapetus is the outermost of Saturn's large moons",
+ toolTipProps: { position: 'bottom' },
+ },
+ ]);
+
+ return (
+ setOptions(newOptions)}
+ >
+ {(list) => list}
+
+ );
+};
diff --git a/src/components/selectable/selectable.stories.tsx b/src/components/selectable/selectable.stories.tsx
new file mode 100644
index 00000000000..467189b76bb
--- /dev/null
+++ b/src/components/selectable/selectable.stories.tsx
@@ -0,0 +1,150 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React, { useState } from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+
+import {
+ enableFunctionToggleControls,
+ hideStorybookControls,
+} from '../../../.storybook/utils';
+
+import { EuiSelectableOption } from './selectable_option';
+import {
+ EuiSelectable,
+ EuiSelectableOnChangeEvent,
+ EuiSelectableProps,
+} from './selectable';
+
+const toolTipProps = {
+ toolTipContent: 'This is a tooltip!',
+ toolTipProps: { position: 'left' as const },
+ value: 4,
+};
+
+const options: EuiSelectableOption[] = [
+ {
+ label: 'Titan',
+ 'data-test-subj': 'titanOption',
+ },
+ {
+ label: 'Enceladus is disabled',
+ disabled: true,
+ },
+ {
+ label: 'Mimas',
+ checked: 'on',
+ },
+ {
+ label: 'Dione',
+ },
+ {
+ label: 'Iapetus',
+ checked: 'on',
+ },
+ {
+ label: 'Phoebe',
+ },
+ {
+ label: 'Rhea',
+ },
+ {
+ label:
+ "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
+ },
+ {
+ label: 'Tethys',
+ },
+ {
+ label: 'Hyperion',
+ },
+];
+
+const meta: Meta = {
+ title: 'Forms/EuiSelectable',
+ component: EuiSelectable,
+ argTypes: {
+ singleSelection: { control: 'radio', options: [true, false, 'always'] },
+ emptyMessage: { control: 'text' },
+ loadingMessage: { control: 'text' },
+ noMatchesMessage: { control: 'text' },
+ selectableScreenReaderText: { control: 'text' },
+ },
+ args: {
+ searchable: false,
+ singleSelection: false,
+ isPreFiltered: false,
+ },
+};
+hideStorybookControls(meta, ['aria-label']);
+
+export default meta;
+type Story = StoryObj;
+
+export const Playground: Story = {
+ args: {
+ options,
+ // setting up for easier testing/QA
+ allowExclusions: false,
+ isLoading: false,
+ emptyMessage: '',
+ loadingMessage: '',
+ noMatchesMessage: '',
+ selectableScreenReaderText: '',
+ searchProps: {
+ 'data-test-subj': 'selectableSearchHere',
+ },
+ },
+ render: ({ ...args }: EuiSelectableProps) => ,
+};
+enableFunctionToggleControls(Playground, ['onChange', 'onActiveOptionChange']);
+
+export const WithTooltip: Story = {
+ parameters: {
+ controls: {
+ include: ['options', 'singleSelection', 'searchable'],
+ },
+ },
+ args: {
+ options: options.map((option) => ({ ...option, ...toolTipProps })),
+ searchable: false,
+ },
+ render: ({ ...args }: EuiSelectableProps) => ,
+};
+
+const StatefulSelectable = ({
+ options,
+ onChange,
+ ...rest
+}: EuiSelectableProps) => {
+ const [selectableOptions, setOptions] = useState(options);
+
+ const handleOnChange = (
+ options: EuiSelectableOption[],
+ event: EuiSelectableOnChangeEvent,
+ changedOption: EuiSelectableOption
+ ) => {
+ setOptions(options);
+ onChange?.(options, event, changedOption);
+ };
+
+ return (
+
+ {(list, search) => (
+ <>
+ {search}
+ {list}
+ >
+ )}
+
+ );
+};
diff --git a/src/components/selectable/selectable_list/__snapshots__/selectable_list_item.test.tsx.snap b/src/components/selectable/selectable_list/__snapshots__/selectable_list_item.test.tsx.snap
index e14f6d4dfa9..793ebda150a 100644
--- a/src/components/selectable/selectable_list/__snapshots__/selectable_list_item.test.tsx.snap
+++ b/src/components/selectable/selectable_list/__snapshots__/selectable_list_item.test.tsx.snap
@@ -506,3 +506,143 @@ exports[`EuiSelectableListItem props textWrap can be "wrap" 1`] = `
`;
+
+exports[`EuiSelectableListItem props tooltip behavior on mouseover 1`] = `
+
+