Repository: elastic/eui (TypeScript)

Issue:
[EuiInlineEdit] Create `placeholder` prop for Inline Edit compoents
**Is your feature request related to a problem? Please describe.**
The inline edit pattern in Stack Management is similar to the `EuiInlineEdit` component, however, it has two display options for `readMode`. It can either:
- Display a default value that populates the field text form control in `editMode`
- Display a placeholder value that does not populate the field text form control in `editMode`

<img width="785" alt="image" src="https://github.com/elastic/eui/assets/40739624/2a95009d-1eee-4c43-9349-1025f4f6459c">

Component Reference: `<InlineTextInput />`
Path: `x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/pipeline_processors_editor_item/inline_text_input.tsx`


**Describe the solution you'd like**
- Create a boolean prop to determine if the default value should be displayed as a placeholder or not
- When the boolean is set to true, the `editMode` field text value will default to an empty string. 
Consumers will still need to implement validation to ensure that empty values cannot be stored.

**Additional context**
Related to #6778




Fix (patch):
diff --git a/src-docs/src/views/inline_edit/inline_edit_example.js b/src-docs/src/views/inline_edit/inline_edit_example.js
index 5c57e1ca5ae..ebe59fa12f2 100644
--- a/src-docs/src/views/inline_edit/inline_edit_example.js
+++ b/src-docs/src/views/inline_edit/inline_edit_example.js
@@ -30,6 +30,14 @@ const inlineEditTitleSnippet = `<EuiInlineEditTitle
   size="m"
 />`;
 
+import InlineEditPlaceholder from './inline_edit_placeholder';
+const inlineEditPlaceholderSource = require('!!raw-loader!./inline_edit_placeholder');
+const inlineEditPlaceholderSnippet = `<EuiInlineEditText
+  inputAriaLabel="Edit text inline"
+  defaultValue=""
+  placeholder="This is placeholder text!"
+/>`;
+
 import InlineEditSave from './inline_edit_save';
 const inlineEditSaveSource = require('!!raw-loader!././inline_edit_save');
 const inlineEditModeSaveSnippet = `<EuiInlineEditText
@@ -194,6 +202,27 @@ export const InlineEditExample = {
       ],
       demo: <InlineEditValidation />,
     },
+    {
+      title: 'Setting placeholder instructions',
+      text: (
+        <>
+          <p>
+            The <EuiCode>placeholder</EuiCode> property will display in both
+            read and edit mode whenever the <strong>EuiInlineEdit</strong>'s
+            value is empty. Use placeholder text to provide guidance or
+            instructions to consumers as to what they're editing.
+          </p>
+        </>
+      ),
+      source: [
+        {
+          type: GuideSectionTypes.TSX,
+          code: inlineEditPlaceholderSource,
+        },
+      ],
+      demo: <InlineEditPlaceholder />,
+      snippet: inlineEditPlaceholderSnippet,
+    },
     {
       title: 'Start in edit mode',
       text: (
diff --git a/src-docs/src/views/inline_edit/inline_edit_placeholder.tsx b/src-docs/src/views/inline_edit/inline_edit_placeholder.tsx
new file mode 100644
index 00000000000..936f8d581f6
--- /dev/null
+++ b/src-docs/src/views/inline_edit/inline_edit_placeholder.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+
+import {
+  EuiInlineEditText,
+  EuiInlineEditTitle,
+  EuiSpacer,
+} from '../../../../src';
+
+export default () => {
+  return (
+    <>
+      <EuiInlineEditText
+        inputAriaLabel="Placeholder text example"
+        defaultValue=""
+        placeholder="Add a description"
+      />
+
+      <EuiSpacer />
+
+      <EuiInlineEditTitle
+        heading="h3"
+        inputAriaLabel="Placeholder title example"
+        defaultValue=""
+        placeholder="Set your username"
+      />
+    </>
+  );
+};
diff --git a/src/components/inline_edit/inline_edit_form.styles.ts b/src/components/inline_edit/inline_edit_form.styles.ts
index d0ecc5c4218..9bac7621573 100644
--- a/src/components/inline_edit/inline_edit_form.styles.ts
+++ b/src/components/inline_edit/inline_edit_form.styles.ts
@@ -7,7 +7,7 @@
  */
 
 import { css } from '@emotion/react';
-import { UseEuiTheme } from '../../services';
+import { UseEuiTheme, tint } from '../../services';
 
 export const euiInlineEditReadModeStyles = ({ euiTheme }: UseEuiTheme) => {
   return {
@@ -21,5 +21,12 @@ export const euiInlineEditReadModeStyles = ({ euiTheme }: UseEuiTheme) => {
         user-select: text;
       }
     `,
+
+    hasPlaceholder: css`
+      .euiText,
+      .euiTitle {
+        color: ${tint(euiTheme.colors.subduedText, 0.08)};
+      }
+    `,
   };
 };
diff --git a/src/components/inline_edit/inline_edit_form.tsx b/src/components/inline_edit/inline_edit_form.tsx
index 3793f5e5213..90feb3c86a7 100644
--- a/src/components/inline_edit/inline_edit_form.tsx
+++ b/src/components/inline_edit/inline_edit_form.tsx
@@ -40,6 +40,7 @@ import { euiInlineEditReadModeStyles } from './inline_edit_form.styles';
 export type EuiInlineEditCommonProps = HTMLAttributes<HTMLDivElement> &
   CommonProps & {
     defaultValue: string;
+    placeholder?: string;
     /**
      * Callback that fires when a user clicks the save button.
      * Passes the current edited text value as an argument.
@@ -121,6 +122,7 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
   children,
   sizes,
   defaultValue,
+  placeholder,
   inputAriaLabel,
   startWithEditOpen,
   readModeProps,
@@ -134,12 +136,6 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
 
   const euiTheme = useEuiTheme();
 
-  const readModeStyles = euiInlineEditReadModeStyles(euiTheme);
-  const readModeCssStyles = [
-    readModeStyles.euiInlineEditReadMode,
-    isReadOnly && readModeStyles.isReadOnly,
-  ];
-
   const { controlHeight, controlCompressedHeight } = euiFormVariables(euiTheme);
   const loadingSkeletonSize = sizes.compressed
     ? controlCompressedHeight
@@ -172,6 +168,13 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
   const [editModeValue, setEditModeValue] = useState(defaultValue);
   const [readModeValue, setReadModeValue] = useState(defaultValue);
 
+  const readModeStyles = euiInlineEditReadModeStyles(euiTheme);
+  const readModeCssStyles = [
+    readModeStyles.euiInlineEditReadMode,
+    isReadOnly && readModeStyles.isReadOnly,
+    placeholder && !readModeValue && readModeStyles.hasPlaceholder,
+  ];
+
   const activateEditMode = () => {
     setIsEditing(true);
     // Waits a tick for state to settle and the focus target to render
@@ -234,6 +237,7 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
             isInvalid={isInvalid}
             isLoading={isLoading}
             data-test-subj="euiInlineEditModeInput"
+            placeholder={placeholder}
             {...editModeProps?.inputProps}
             inputRef={setEditModeRefs}
             onChange={(e) => {
@@ -337,7 +341,7 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
           readModeProps?.onClick?.(e);
         }}
       >
-        {children(readModeValue)}
+        {children(readModeValue || placeholder)}
       </EuiButtonEmpty>
       <span id={readModeDescribedById} hidden>
         {!isReadOnly && (
diff --git a/src/components/inline_edit/inline_edit_text.tsx b/src/components/inline_edit/inline_edit_text.tsx
index 8015b7ac141..217916954a3 100644
--- a/src/components/inline_edit/inline_edit_text.tsx
+++ b/src/components/inline_edit/inline_edit_text.tsx
@@ -32,6 +32,7 @@ export const EuiInlineEditText: FunctionComponent<EuiInlineEditTextProps> = ({
   className,
   size = 'm',
   defaultValue,
+  placeholder,
   inputAriaLabel,
   startWithEditOpen,
   readModeProps: _readModeProps,
@@ -62,6 +63,7 @@ export const EuiInlineEditText: FunctionComponent<EuiInlineEditTextProps> = ({
   const formProps = {
     sizes,
     defaultValue,
+    placeholder,
     inputAriaLabel,
     startWithEditOpen,
     readModeProps,
diff --git a/src/components/inline_edit/inline_edit_title.tsx b/src/components/inline_edit/inline_edit_title.tsx
index 37c1ebae218..aa87d82bf26 100644
--- a/src/components/inline_edit/inline_edit_title.tsx
+++ b/src/components/inline_edit/inline_edit_title.tsx
@@ -39,6 +39,7 @@ export const EuiInlineEditTitle: FunctionComponent<EuiInlineEditTitleProps> = ({
   size = 'm',
   heading,
   defaultValue,
+  placeholder,
   inputAriaLabel,
   startWithEditOpen,
   readModeProps: _readModeProps,
@@ -78,6 +79,7 @@ export const EuiInlineEditTitle: FunctionComponent<EuiInlineEditTitleProps> = ({
   const formProps = {
     sizes,
     defaultValue,
+    placeholder,
     inputAriaLabel,
     startWithEditOpen,
     readModeProps,
diff --git a/upcoming_changelogs/6883.md b/upcoming_changelogs/6883.md
new file mode 100644
index 00000000000..a1dc6279886
--- /dev/null
+++ b/upcoming_changelogs/6883.md
@@ -0,0 +1,1 @@
+- Added `placeholder` prop to `EuiInlineEdit`