feat(select): add helperText and errorText properties (#30143)

Issue number: resolves #29205

---------

## What is the current behavior?
Select does not support helper and error text.

## What is the new behavior?
- Adds support for `helperText` and `errorText`
- Adds parts for `helper-text`, `error-text` and `supporting-text`
- Adds an e2e test for helper and error text with functional tests and
screenshot tests

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

## Other information


[Preview](https://ionic-framework-git-rou-11551-ionic1.vercel.app/src/components/select/test/bottom-content)

---------

Co-authored-by: swimer11 <65334157+swimer11@users.noreply.github.com>

---------

Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
Brandy Smith
2025-03-10 18:53:11 -04:00
committed by GitHub
parent 94ca2e54cb
commit bbdaec0cc1
50 changed files with 521 additions and 2 deletions

View File

@@ -1626,8 +1626,10 @@ ion-select,prop,cancelText,string,'Cancel',false,false
ion-select,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-select,prop,compareWith,((currentValue: any, compareValue: any) => boolean) | null | string | undefined,undefined,false,false
ion-select,prop,disabled,boolean,false,false,false
ion-select,prop,errorText,string | undefined,undefined,false,false
ion-select,prop,expandedIcon,string | undefined,undefined,false,false
ion-select,prop,fill,"outline" | "solid" | undefined,undefined,false,false
ion-select,prop,helperText,string | undefined,undefined,false,false
ion-select,prop,interface,"action-sheet" | "alert" | "modal" | "popover",'alert',false,false
ion-select,prop,interfaceOptions,any,{},false,false
ion-select,prop,justify,"end" | "space-between" | "start" | undefined,undefined,false,false
@@ -1682,9 +1684,12 @@ ion-select,css-prop,--placeholder-opacity,md
ion-select,css-prop,--ripple-color,ios
ion-select,css-prop,--ripple-color,md
ion-select,part,container
ion-select,part,error-text
ion-select,part,helper-text
ion-select,part,icon
ion-select,part,label
ion-select,part,placeholder
ion-select,part,supporting-text
ion-select,part,text
ion-select-modal,scoped

View File

@@ -2771,6 +2771,10 @@ export namespace Components {
* If `true`, the user cannot interact with the select.
*/
"disabled": boolean;
/**
* Text that is placed under the select and displayed when an error is detected.
*/
"errorText"?: string;
/**
* The toggle icon to show when the select is open. If defined, the icon rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon` will be used for when the select is both open and closed.
*/
@@ -2779,6 +2783,10 @@ export namespace Components {
* The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available in `md` mode.
*/
"fill"?: 'outline' | 'solid';
/**
* Text that is placed under the select and displayed when no error is detected.
*/
"helperText"?: string;
/**
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
*/
@@ -7616,6 +7624,10 @@ declare namespace LocalJSX {
* If `true`, the user cannot interact with the select.
*/
"disabled"?: boolean;
/**
* Text that is placed under the select and displayed when an error is detected.
*/
"errorText"?: string;
/**
* The toggle icon to show when the select is open. If defined, the icon rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon` will be used for when the select is both open and closed.
*/
@@ -7624,6 +7636,10 @@ declare namespace LocalJSX {
* The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available in `md` mode.
*/
"fill"?: 'outline' | 'solid';
/**
* Text that is placed under the select and displayed when no error is detected.
*/
"helperText"?: string;
/**
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
*/

View File

@@ -5,6 +5,8 @@
// --------------------------------------------------
:host {
--border-width: #{$hairlines-width};
--border-color: #{$item-ios-border-color};
--highlight-height: 0px;
}

View File

@@ -32,6 +32,10 @@
--border-color: var(--highlight-color);
}
/**
* The bottom content should never have
* a border with the solid style.
*/
:host(.select-fill-solid) .select-bottom {
border-top: none;
}

View File

@@ -275,6 +275,71 @@ button {
--highlight-color: var(--highlight-color-valid);
}
// Select Bottom Content
// ----------------------------------------------------------------
.select-bottom {
/**
* The bottom content should take on the start and end
* padding so it is always aligned with either the label
* or the start of the text select.
*/
@include padding(5px, var(--padding-end), 0, var(--padding-start));
display: flex;
justify-content: space-between;
border-top: var(--border-width) var(--border-style) var(--border-color);
font-size: dynamic-font(12px);
white-space: normal;
}
/**
* If the select has a validity state, the
* border and label should reflect that as a color.
* The invalid state should show if the select is
* invalid and has already been touched.
* The valid state should show if the select
* is valid, has already been touched, and
* is currently focused. Do not show the valid
* highlight when the select is blurred.
*/
:host(.has-focus.ion-valid),
:host(.ion-touched.ion-invalid) {
--border-color: var(--highlight-color);
}
// Select Hint Text
// ----------------------------------------------------------------
/**
* Error text should only be shown when .ion-invalid is
* present on the select. Otherwise the helper text should
* be shown.
*/
.select-bottom .error-text {
display: none;
color: var(--highlight-color-invalid);
}
.select-bottom .helper-text {
display: block;
color: $text-color-step-300;
}
:host(.ion-touched.ion-invalid) .select-bottom .error-text {
display: block;
}
:host(.ion-touched.ion-invalid) .select-bottom .helper-text {
display: none;
}
// Select Label
// ----------------------------------------------------------------

View File

@@ -41,6 +41,9 @@ import type { SelectChangeEventDetail, SelectInterface, SelectCompareFn } from '
* @part icon - The select icon container.
* @part container - The container for the selected text or placeholder.
* @part label - The label text describing the select.
* @part supporting-text - Supporting text displayed beneath the select.
* @part helper-text - Supporting text displayed beneath the select when the select is valid.
* @part error-text - Supporting text displayed beneath the select when the select is invalid and touched.
*/
@Component({
tag: 'ion-select',
@@ -52,6 +55,8 @@ import type { SelectChangeEventDetail, SelectInterface, SelectCompareFn } from '
})
export class Select implements ComponentInterface {
private inputId = `ion-sel-${selectIds++}`;
private helperTextId = `${this.inputId}-helper-text`;
private errorTextId = `${this.inputId}-error-text`;
private overlay?: OverlaySelect;
private focusEl?: HTMLButtonElement;
private mutationO?: MutationObserver;
@@ -98,6 +103,16 @@ export class Select implements ComponentInterface {
*/
@Prop() fill?: 'outline' | 'solid';
/**
* Text that is placed under the select and displayed when an error is detected.
*/
@Prop() errorText?: string;
/**
* Text that is placed under the select and displayed when no error is detected.
*/
@Prop() helperText?: string;
/**
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
*/
@@ -1014,6 +1029,8 @@ export class Select implements ComponentInterface {
aria-label={this.ariaLabel}
aria-haspopup="dialog"
aria-expanded={`${isExpanded}`}
aria-describedby={this.getHintTextID()}
aria-invalid={this.getHintTextID() === this.errorTextId}
aria-required={`${required}`}
onFocus={this.onFocus}
onBlur={this.onBlur}
@@ -1022,6 +1039,55 @@ export class Select implements ComponentInterface {
);
}
private getHintTextID(): string | undefined {
const { el, helperText, errorText, helperTextId, errorTextId } = this;
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
/**
* Renders the helper text or error text values
*/
private renderHintText() {
const { helperText, errorText, helperTextId, errorTextId } = this;
return [
<div id={helperTextId} class="helper-text" part="supporting-text helper-text">
{helperText}
</div>,
<div id={errorTextId} class="error-text" part="supporting-text error-text">
{errorText}
</div>,
];
}
/**
* Responsible for rendering helper text, and error text. This element
* should only be rendered if hint text is set.
*/
private renderBottomContent() {
const { helperText, errorText } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
if (!hasHintText) {
return;
}
return <div class="select-bottom">{this.renderHintText()}</div>;
}
render() {
const { disabled, el, isExpanded, expandedIcon, labelPlacement, justify, placeholder, fill, shape, name, value } =
this;
@@ -1101,6 +1167,7 @@ export class Select implements ComponentInterface {
{hasFloatingOrStackedLabel && this.renderSelectIcon()}
{shouldRenderHighlight && <div class="select-highlight"></div>}
</label>
{this.renderBottomContent()}
</Host>
);
}

View File

@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Select - Bottom Content</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
}
ion-select.custom-error-color {
--highlight-color-invalid: purple;
}
</style>
</head>
<body onLoad="onLoad()">
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Select - Bottom Content</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content" class="ion-padding">
<div class="grid">
<div class="grid-item">
<h2>No Hint</h2>
<ion-select label="Label">
<ion-select-option>Option</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>No Hint: Stacked</h2>
<ion-select label="Label" label-placement="stacked">
<ion-select-option>Option</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Helper Text</h2>
<ion-select label="Label" helper-text="Helper text">
<ion-select-option>Option</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Helper Text: Stacked</h2>
<ion-select label="Label" label-placement="stacked" helper-text="Helper text"
>Label
<ion-select-option>Option</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Error Text</h2>
<ion-select class="ion-touched ion-invalid" label="Label" error-text="Error text">
<ion-select-option>Option</ion-select-option></ion-select
>
</div>
<div class="grid-item">
<h2>Error Text: Stacked</h2>
<ion-select class="ion-touched ion-invalid" label="Label" label-placement="stacked" error-text="Error text">
<ion-select-option>Option</ion-select-option></ion-select
>
</div>
<div class="grid-item">
<h2>Error Text: Custom Color</h2>
<ion-select class="ion-touched ion-invalid custom-error-color" label="Label" error-text="Error text">
<ion-select-option>Option</ion-select-option></ion-select
>
</div>
<div class="grid-item">
<h2>Helper Text: Wrapping</h2>
<ion-select
label="Label"
helper-text="Helper text helper text helper text helper text helper text helper text helper text helper text helper text"
>
<ion-select-option>Option</ion-select-option>
</ion-select>
</div>
</div>
<button class="expand" onclick="toggleFill()">Toggle Fill</button>
</ion-content>
</ion-app>
<script>
// Hide the toggle fill button on ios mode since it's not supported
function onLoad() {
const toggleFillButton = document.querySelector('button');
if (Ionic.mode === 'ios' && toggleFillButton) {
toggleFillButton.style.display = 'none';
}
}
const selects = document.querySelectorAll('ion-select');
function toggleFill() {
selects.forEach((select) => {
switch (select.fill) {
case 'outline':
select.fill = 'solid';
break;
case 'solid':
select.fill = undefined;
break;
default:
select.fill = 'outline';
}
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,215 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* Functionality is the same across modes & directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('select: bottom content functionality'), () => {
test('should not render bottom content if no hint is enabled', async ({ page }) => {
await page.setContent(`<ion-select label="Label"></ion-select>`, config);
const bottomEl = page.locator('ion-select .select-bottom');
await expect(bottomEl).toHaveCount(0);
});
test('helper text should be visible initially', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const helperText = page.locator('ion-select .helper-text');
const errorText = page.locator('ion-select .error-text');
await expect(helperText).toBeVisible();
await expect(helperText).toHaveText('Helper text');
await expect(errorText).toBeHidden();
});
test('select should have an aria-describedby attribute when helper text is present', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const select = page.locator('ion-select button');
const helperText = page.locator('ion-select .helper-text');
const helperTextId = await helperText.getAttribute('id');
const ariaDescribedBy = await select.getAttribute('aria-describedby');
expect(ariaDescribedBy).toBe(helperTextId);
});
test('error text should be visible when select is invalid', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const helperText = page.locator('ion-select .helper-text');
const errorText = page.locator('ion-select .error-text');
await expect(helperText).toBeHidden();
await expect(errorText).toBeVisible();
await expect(errorText).toHaveText('Error text');
});
test('select should have an aria-describedby attribute when error text is present', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const select = page.locator('ion-select button');
const errorText = page.locator('ion-select .error-text');
const errorTextId = await errorText.getAttribute('id');
const ariaDescribedBy = await select.getAttribute('aria-describedby');
expect(ariaDescribedBy).toBe(errorTextId);
});
test('select should have aria-invalid attribute when select is invalid', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" class="ion-invalid ion-touched" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const select = page.locator('ion-select button');
await expect(select).toHaveAttribute('aria-invalid');
});
test('select should not have aria-invalid attribute when select is valid', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" helper-text="Helper text" error-text="Error text"></ion-select>`,
config
);
const select = page.locator('ion-select button');
await expect(select).not.toHaveAttribute('aria-invalid');
});
test('select should not have aria-describedby attribute when no hint or error text is present', async ({
page,
}) => {
await page.setContent(`<ion-select label="Label"></ion-select>`, config);
const select = page.locator('ion-select button');
await expect(select).not.toHaveAttribute('aria-describedby');
});
});
});
/**
* Rendering is different across modes
*/
configs({ modes: ['ios', 'md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('select: helper text rendering'), () => {
test('should not have visual regressions when rendering helper text', async ({ page }) => {
await page.setContent(`<ion-select label="Label" helper-text="Helper text"></ion-select>`, config);
const bottomEl = page.locator('ion-select');
await expect(bottomEl).toHaveScreenshot(screenshot(`select-helper-text`));
});
test('should not have visual regressions when rendering helper text with wrapping text', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" helper-text="Helper text helper text helper text helper text helper text helper text helper text helper text helper text"></ion-select>`,
config
);
const bottomEl = page.locator('ion-select');
await expect(bottomEl).toHaveScreenshot(screenshot(`select-helper-text-wrapping`));
});
test('should not have visual regressions when rendering helper text with a stacked label', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" label-placement="stacked" helper-text="Helper text"></ion-select>`,
config
);
const bottomEl = page.locator('ion-select');
await expect(bottomEl).toHaveScreenshot(screenshot(`select-helper-text-stacked-label`));
});
});
test.describe(title('select: error text rendering'), () => {
test('should not have visual regressions when rendering error text', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" class="ion-invalid ion-touched" error-text="Error text"></ion-select>`,
config
);
const bottomEl = page.locator('ion-select');
await expect(bottomEl).toHaveScreenshot(screenshot(`select-error-text`));
});
test('should not have visual regressions when rendering error text with a stacked label', async ({ page }) => {
await page.setContent(
`<ion-select label="Label" class="ion-invalid ion-touched" error-text="Error text" label-placement="stacked"></ion-select>`,
config
);
const bottomEl = page.locator('ion-select');
await expect(bottomEl).toHaveScreenshot(screenshot(`select-error-text-stacked-label`));
});
});
});
/**
* Customizing supporting text is the same across modes and directions
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('select: supporting text customization'), () => {
test('should not have visual regressions when rendering helper text with custom css', async ({ page }) => {
await page.setContent(
`
<style>
ion-select::part(supporting-text) {
font-size: 20px;
}
ion-select::part(helper-text) {
color: green;
}
</style>
<ion-select label="Label" helper-text="Helper text"></ion-select>
`,
config
);
const helperText = page.locator('ion-select');
await expect(helperText).toHaveScreenshot(screenshot(`select-helper-text-custom-css`));
});
test('should not have visual regressions when rendering error text with custom css', async ({ page }) => {
await page.setContent(
`
<style>
ion-select::part(supporting-text) {
font-size: 20px;
}
ion-select::part(error-text) {
color: purple;
}
</style>
<ion-select class="ion-invalid ion-touched" label="Label" error-text="Error text"></ion-select>
`,
config
);
const errorText = page.locator('ion-select');
await expect(errorText).toHaveScreenshot(screenshot(`select-error-text-custom-css`));
});
test('should not have visual regressions when rendering error text with a custom css variable', async ({
page,
}) => {
await page.setContent(
`
<style>
ion-select {
--highlight-color-invalid: purple;
}
</style>
<ion-select class="ion-invalid ion-touched" label="Label" error-text="Error text"></ion-select>
`,
config
);
const errorText = page.locator('ion-select');
await expect(errorText).toHaveScreenshot(screenshot(`select-error-text-custom-css-var`));
});
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -2060,7 +2060,7 @@ export declare interface IonSegmentView extends Components.IonSegmentView {
@ProxyCmp({
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'required', 'selectedText', 'shape', 'toggleIcon', 'value'],
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'errorText', 'expandedIcon', 'fill', 'helperText', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'required', 'selectedText', 'shape', 'toggleIcon', 'value'],
methods: ['open']
})
@Component({
@@ -2068,7 +2068,7 @@ export declare interface IonSegmentView extends Components.IonSegmentView {
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'required', 'selectedText', 'shape', 'toggleIcon', 'value'],
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'errorText', 'expandedIcon', 'fill', 'helperText', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'required', 'selectedText', 'shape', 'toggleIcon', 'value'],
})
export class IonSelect {
protected el: HTMLIonSelectElement;

View File

@@ -21,8 +21,10 @@ const SELECT_INPUTS = [
'color',
'compareWith',
'disabled',
'errorText',
'expandedIcon',
'fill',
'helperText',
'interface',
'interfaceOptions',
'justify',

View File

@@ -872,6 +872,8 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect, JSX.IonSel
'compareWith',
'disabled',
'fill',
'errorText',
'helperText',
'interface',
'interfaceOptions',
'justify',