EnumerationInput Component#
EnumerationInput is the form input component used to render enumeration-type schema attributes as a SingleSelect dropdown in the Strapi admin. It lives at packages/core/admin/admin/src/components/FormInputs/Enumeration.tsx and is exported as a memoized component .
How It Works#
The component wraps @strapi/design-system's Field.Root + SingleSelect using the Design System v2 API . It reads its value and error state from the form context via useField and maps the options array to SingleSelectOption elements .
It is routed from InputRenderer whenever type: 'enumeration' is encountered.
Hardcoded Placeholder Option#
The component always injects a "Choose here" placeholder as the first SingleSelectOption, unconditionally :
- The option has
value="". - When
required={true}, it is rendered withdisabledandhiddenso it cannot be selected. - The text comes from the i18n key
components.InputSelect.option.placeholder(default:"Choose here").
This placeholder is built into the component's render output, not controlled by the placeholder prop passed to it.
The Placeholder Prop Conflict (Bug)#
EnumerationProps extends InputProps, which includes an optional placeholder?: string property . Callers can and do pass a placeholder to enumeration fields — e.g.:
SingleSignOnPage.tsx— the "Default role" field passesplaceholder: formatMessage({ id: 'components.InputSelect.option.placeholder', defaultMessage: 'Choose here' }).ProfilePage.tsx— both the "Language preference" and "Interface mode" fields pass aplaceholderprop .
However, EnumerationInput spreads ...props onto SingleSelect but never extracts or uses the placeholder prop to control its built-in placeholder option. The result depends on how SingleSelect interprets a placeholder prop:
- Duplication (reported bug): When the caller passes a placeholder whose text matches the hardcoded one, the Design System v2
SingleSelectrenders it as a second "Choose here" entry alongside the one injected byEnumerationInput. This is the behavior confirmed in issue #27283 on Strapi v5.51.2 for the SSO "Default role" field . - Silent discard (ProfilePage): When the placeholder differs from the hardcoded text (e.g.,
"Select"), the caller-supplied value is silently ignored and the built-in"Choose here"is shown instead.
Root Cause and Design System v2 Context#
This conflict was likely introduced during the Design System v2 migration. In the v1 API, placeholder was a direct prop on the select component and the component did not inject its own placeholder option. In v2, the API shifted to a composite Field.Root + SingleSelect model . The EnumerationInput was rewritten to hardcode the placeholder as a <SingleSelectOption> child, but callers were not updated to remove their now-redundant placeholder props.
Affected Locations#
| File | Field | Passed placeholder | Observed effect |
|---|---|---|---|
SingleSignOnPage.tsx | defaultRole | "Choose here" | Duplicate "Choose here" entries (issue #27283) |
ProfilePage.tsx | preferedLanguage, currentTheme | "Select" | Placeholder silently ignored; "Choose here" shown |
Fix#
For each affected enumeration field, remove the redundant placeholder property from the field definition. EnumerationInput manages its own placeholder option internally; explicit placeholder props have no effect and can cause duplication .
If per-field customization of the placeholder text is needed, the component itself would need to be updated to conditionally render the placeholder option based on a prop rather than always hardcoding it.
Key Source References#
Enumeration.tsx— component implementationtypes.ts—EnumerationPropsandInputPropstype definitionsSingleSignOnPage.tsx— affected SSO field (duplicate placeholder bug)ProfilePage.tsx— affected profile fields (silent discard)- GitHub issue #27283 — confirmed bug report, Strapi v5.51.2