Skip to content

feat: Support placeholders in S2 components#8692

Merged
devongovett merged 18 commits intomainfrom
placeholder_s2
Sep 26, 2025
Merged

feat: Support placeholders in S2 components#8692
devongovett merged 18 commits intomainfrom
placeholder_s2

Conversation

@LFDanLu
Copy link
Copy Markdown
Member

@LFDanLu LFDanLu commented Aug 8, 2025

Closes RSP Component Milestones (view)

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Test placeholders for TextField/Area, Combobox, Picker, ColorArea, NumberField, SearchField. Note that there should be a warning that fires if a placeholder/value isn't present and the input isn't focused

🧢 Your Project:

RSP

@rspbot
Copy link
Copy Markdown

rspbot commented Aug 8, 2025

Comment thread packages/@react-spectrum/s2/src/ColorField.tsx
Comment thread packages/@react-spectrum/s2/src/placeholder-utils.tsx Outdated
reidbarber
reidbarber previously approved these changes Aug 11, 2025
Comment thread packages/@react-spectrum/s2/src/placeholder-utils.tsx Outdated
@rspbot
Copy link
Copy Markdown

rspbot commented Aug 11, 2025

Comment thread packages/@react-spectrum/s2/src/placeholder-utils.tsx Outdated
Comment thread packages/@react-spectrum/s2/src/placeholder-utils.tsx Outdated
Comment thread packages/@react-spectrum/s2/src/Field.tsx
Comment thread packages/@react-spectrum/s2/src/NumberField.tsx Outdated
@rspbot
Copy link
Copy Markdown

rspbot commented Aug 12, 2025

Comment thread packages/@react-spectrum/s2/src/placeholder-utils.tsx Outdated
@rspbot
Copy link
Copy Markdown

rspbot commented Aug 12, 2025

snowystinger
snowystinger previously approved these changes Aug 12, 2025
@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Aug 26, 2025

closing for now, waiting on audit ~eta mid sep

@LFDanLu LFDanLu closed this Aug 26, 2025
@LFDanLu LFDanLu reopened this Sep 23, 2025
@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Sep 23, 2025

TODO: remove placeholder warning, add to docs in new docs

@rspbot
Copy link
Copy Markdown

rspbot commented Sep 24, 2025

snowystinger
snowystinger previously approved these changes Sep 24, 2025
Comment thread packages/@react-spectrum/s2/stories/ComboBox.stories.tsx Outdated
Comment thread packages/@react-spectrum/s2/stories/TextField.stories.tsx Outdated
@rspbot
Copy link
Copy Markdown

rspbot commented Sep 25, 2025

Copy link
Copy Markdown
Member

@yihuiliao yihuiliao Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the example under the Actions section is missing a placeholder

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, looks like that example got pulled in from the merge from main, I'll update

@rspbot
Copy link
Copy Markdown

rspbot commented Sep 25, 2025

reidbarber
reidbarber previously approved these changes Sep 25, 2025
yihuiliao
yihuiliao previously approved these changes Sep 25, 2025
@devongovett devongovett dismissed stale reviews from yihuiliao and reidbarber via b80a5d4 September 25, 2025 23:27
@rspbot
Copy link
Copy Markdown

rspbot commented Sep 25, 2025

@rspbot
Copy link
Copy Markdown

rspbot commented Sep 25, 2025

## API Changes

react-aria-components

/react-aria-components:Input

 Input extends InputHTMLAttributes {
   className?: ClassNameOrFunction<InputRenderProps>
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onHoverStart?: (HoverEvent) => void
+  placeholder?: string
   style?: StyleOrFunction<InputRenderProps>
 }

/react-aria-components:InputProps

 InputProps {
   className?: ClassNameOrFunction<InputRenderProps>
   onHoverChange?: (boolean) => void
   onHoverEnd?: (HoverEvent) => void
   onHoverStart?: (HoverEvent) => void
+  placeholder?: string
   style?: StyleOrFunction<InputRenderProps>
 }

@react-spectrum/s2

/@react-spectrum/s2:ColorField

 ColorField {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   channel?: ColorChannel
   colorSpace?: ColorSpace
   contextualHelp?: ReactNode
   defaultValue?: T
   description?: ReactNode
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   isWheelDisabled?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (Color | null) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   styles?: StylesProp
   validate?: (Color | null) => ValidationError | boolean | null | undefined
   value?: T
 }

/@react-spectrum/s2:ComboBox

 ComboBox <T extends {}> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   align?: 'start' | 'end' = 'start'
   allowsCustomValue?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   children: ReactNode | ({}) => ReactNode
   contextualHelp?: ReactNode
   defaultInputValue?: string
   defaultItems?: Iterable<T>
   defaultSelectedKey?: Key
   dependencies?: ReadonlyArray<any>
   description?: ReactNode
   direction?: 'bottom' | 'top' = 'bottom'
   disabledKeys?: Iterable<Key>
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   form?: string
   formValue?: 'text' | 'key' = 'key'
   id?: string
   inputValue?: string
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   items?: Iterable<T>
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   loadingState?: LoadingState
   menuTrigger?: MenuTriggerAction = 'input'
   menuWidth?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBlur?: (FocusEvent<HTMLInputElement>) => void
   onFocus?: (FocusEvent<HTMLInputElement>) => void
   onFocusChange?: (boolean) => void
   onInputChange?: (string) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onLoadMore?: () => any
   onOpenChange?: (boolean, MenuTriggerAction) => void
   onSelectionChange?: (Key | null) => void
+  placeholder?: string
   selectedKey?: Key | null
   shouldFlip?: boolean = true
   shouldFocusWrap?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   styles?: StylesProp
   validate?: (ComboBoxValidationValue) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
 }

/@react-spectrum/s2:NumberField

 NumberField {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   decrementAriaLabel?: string
   defaultValue?: number
   description?: ReactNode
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   form?: string
   formatOptions?: Intl.NumberFormatOptions
   hideStepper?: boolean = false
   id?: string
   incrementAriaLabel?: string
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   isWheelDisabled?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxValue?: number
   minValue?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (T) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   step?: number
   styles?: StylesProp
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: number
 }

/@react-spectrum/s2:SearchField

 SearchField {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onClear?: () => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
   onSubmit?: (string) => void
   pattern?: string
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   
 }) = 'search'
   validate?: (string) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

/@react-spectrum/s2:TextArea

 TextArea {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

/@react-spectrum/s2:TextField

 TextField {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
   pattern?: string
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   
 }) = 'text'
   validate?: (string) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

/@react-spectrum/s2:ColorFieldProps

 ColorFieldProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   channel?: ColorChannel
   colorSpace?: ColorSpace
   contextualHelp?: ReactNode
   defaultValue?: T
   description?: ReactNode
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   isWheelDisabled?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<Target>) => void
   onChange?: (Color | null) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<Target>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   styles?: StylesProp
   validate?: (Color | null) => ValidationError | boolean | null | undefined
   value?: T
 }

/@react-spectrum/s2:ComboBoxProps

 ComboBoxProps <T extends {}> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   align?: 'start' | 'end' = 'start'
   allowsCustomValue?: boolean
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean
   children: ReactNode | ({}) => ReactNode
   contextualHelp?: ReactNode
   defaultInputValue?: string
   defaultItems?: Iterable<T>
   defaultSelectedKey?: Key
   dependencies?: ReadonlyArray<any>
   description?: ReactNode
   direction?: 'bottom' | 'top' = 'bottom'
   disabledKeys?: Iterable<Key>
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   form?: string
   formValue?: 'text' | 'key' = 'key'
   id?: string
   inputValue?: string
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   items?: Iterable<T>
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   loadingState?: LoadingState
   menuTrigger?: MenuTriggerAction = 'input'
   menuWidth?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBlur?: (FocusEvent<HTMLInputElement>) => void
   onFocus?: (FocusEvent<HTMLInputElement>) => void
   onFocusChange?: (boolean) => void
   onInputChange?: (string) => void
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onLoadMore?: () => any
   onOpenChange?: (boolean, MenuTriggerAction) => void
   onSelectionChange?: (Key | null) => void
+  placeholder?: string
   selectedKey?: Key | null
   shouldFlip?: boolean = true
   shouldFocusWrap?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   styles?: StylesProp
   validate?: (ComboBoxValidationValue) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
 }

/@react-spectrum/s2:SearchFieldProps

 SearchFieldProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onClear?: () => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
   onSubmit?: (string) => void
   pattern?: string
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   
 }) = 'search'
   validate?: (string) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

/@react-spectrum/s2:TextFieldProps

 TextFieldProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
   pattern?: string
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   
 }) = 'text'
   validate?: (string) => ValidationError | boolean | null | undefined
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

/@react-spectrum/s2:TextAreaProps

 TextAreaProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-activedescendant?: string
   aria-autocomplete?: 'none' | 'inline' | 'list' | 'both'
   aria-controls?: string
   aria-describedby?: string
   aria-details?: string
   aria-errormessage?: string
   aria-haspopup?: boolean | 'false' | 'true' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
   aria-label?: string
   aria-labelledby?: string
   autoComplete?: string
   autoCorrect?: string
   autoFocus?: boolean
   contextualHelp?: ReactNode
   defaultValue?: string
   description?: ReactNode
   enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'
   errorMessage?: ReactNode | (ValidationResult) => ReactNode
   excludeFromTabOrder?: boolean
   form?: string
   id?: string
   inputMode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
   isDisabled?: boolean
   isInvalid?: boolean
   isReadOnly?: boolean
   isRequired?: boolean
   label?: ReactNode
   labelAlign?: Alignment = 'start'
   labelPosition?: LabelPosition = 'top'
   maxLength?: number
   minLength?: number
   name?: string
   necessityIndicator?: NecessityIndicator = 'icon'
   onBeforeInput?: FormEventHandler<HTMLInputElement>
   onBlur?: (FocusEvent<T>) => void
   onChange?: (T) => void
   onCompositionEnd?: CompositionEventHandler<HTMLInputElement>
   onCompositionStart?: CompositionEventHandler<HTMLInputElement>
   onCompositionUpdate?: CompositionEventHandler<HTMLInputElement>
   onCopy?: ClipboardEventHandler<HTMLInputElement>
   onCut?: ClipboardEventHandler<HTMLInputElement>
   onFocus?: (FocusEvent<T>) => void
   onFocusChange?: (boolean) => void
   onInput?: FormEventHandler<HTMLInputElement>
   onKeyDown?: (KeyboardEvent) => void
   onKeyUp?: (KeyboardEvent) => void
   onPaste?: ClipboardEventHandler<HTMLInputElement>
   onSelect?: ReactEventHandler<HTMLInputElement>
+  placeholder?: string
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   spellCheck?: string
   styles?: StylesProp
   validationBehavior?: 'native' | 'aria' = 'native'
   value?: string
 }

@devongovett devongovett added this pull request to the merge queue Sep 26, 2025
Merged via the queue into main with commit eba6cc0 Sep 26, 2025
32 checks passed
@devongovett devongovett deleted the placeholder_s2 branch September 26, 2025 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants