Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(input, textarea, select): add section for start and end slots #3271

Merged
merged 10 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/api/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,22 @@ Please submit bug reports with Maskito to the [Maskito Github repository](https:

:::

## Start and End Slots (experimental)

The `start` and `end` slots can be used to place icons, buttons, or prefix/suffix text on either side of the input.

Note that this feature is considered experimental because it relies on a simulated version of [Web Component slots](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots). As a result, the simulated behavior may not exactly match the native slot behavior.

:::note
In most cases, [Icon](./icon.md) components placed in these slots should have `aria-hidden="true"`. See the [Icon accessibility docs](https://ionicframework.com/docs/api/icon#accessibility) for more information.

If slot content is meant to be interacted with, it should be wrapped in an interactive element such as a [Button](./button.md). This ensures that the content can be tabbed to.
averyjohnston marked this conversation as resolved.
Show resolved Hide resolved
:::

import StartEndSlots from '@site/static/usage/v7/input/start-end-slots/index.md';

<StartEndSlots />

## Theming

### Colors
Expand Down
14 changes: 14 additions & 0 deletions docs/api/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,20 @@ import InterfaceOptionsExample from '@site/static/usage/v7/select/customization/

<InterfaceOptionsExample />

## Start and End Slots
averyjohnston marked this conversation as resolved.
Show resolved Hide resolved

The `start` and `end` slots can be used to place icons, buttons, or prefix/suffix text on either side of the select. If the slot content is clicked, the select will not open.

:::note
In most cases, [Icon](./icon.md) components placed in these slots should have `aria-hidden="true"`. See the [Icon accessibility docs](https://ionicframework.com/docs/api/icon#accessibility) for more information.

If slot content is meant to be interacted with, it should be wrapped in an interactive element such as a [Button](./button.md). This ensures that the content can be tabbed to.
averyjohnston marked this conversation as resolved.
Show resolved Hide resolved
:::

thetaPC marked this conversation as resolved.
Show resolved Hide resolved
import StartEndSlots from '@site/static/usage/v7/select/start-end-slots/index.md';

<StartEndSlots />

## Customization

There are two units that make up the Select component and each need to be styled separately. The `ion-select` element is represented on the view by the selected value(s), or placeholder if there is none, and dropdown icon. The interface, which is defined in the [Interfaces](#interfaces) section above, is the dialog that opens when clicking on the `ion-select`. The interface contains all of the options defined by adding `ion-select-option` elements. The following sections will go over the differences between styling these.
Expand Down
16 changes: 16 additions & 0 deletions docs/api/textarea.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ import ClearOnEditPlayground from '@site/static/usage/v7/textarea/clear-on-edit/

<ClearOnEditPlayground />

## Start and End Slots (experimental)

The `start` and `end` slots can be used to place icons, buttons, or prefix/suffix text on either side of the textarea.

Note that this feature is considered experimental because it relies on a simulated version of [Web Component slots](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots). As a result, the simulated behavior may not exactly match the native slot behavior.

:::note
In most cases, [Icon](./icon.md) components placed in these slots should have `aria-hidden="true"`. See the [Icon accessibility docs](https://ionicframework.com/docs/api/icon#accessibility) for more information.

If slot content is meant to be interacted with, it should be wrapped in an interactive element such as a [Button](./button.md). This ensures that the content can be tabbed to.
averyjohnston marked this conversation as resolved.
Show resolved Hide resolved
:::

import StartEndSlots from '@site/static/usage/v7/textarea/start-end-slots/index.md';

<StartEndSlots />

## Migrating from Legacy Textarea Syntax

A simpler textarea syntax was introduced in Ionic 7.0. This new syntax reduces the boilerplate required to setup an textarea, resolves accessibility issues, and improves the developer experience.
Expand Down
12 changes: 12 additions & 0 deletions static/usage/v7/input/start-end-slots/angular.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
```html
<ion-list>
<ion-item>
<ion-input labelPlacement="stacked" label="Email" placeholder="email@domain.com">
<ion-icon slot="start" name="lock-closed" aria-hidden="true"></ion-icon>
<ion-button fill="clear" slot="end" aria-label="Show/hide">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-input>
</ion-item>
</ion-list>
```
31 changes: 31 additions & 0 deletions static/usage/v7/input/start-end-slots/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Input</title>
<link rel="stylesheet" href="../../../common.css" />
<script src="../../../common.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@7/dist/ionic/ionic.esm.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@7/css/ionic.bundle.css" />
</head>

<body>
<ion-app>
<ion-content>
<div class="container">
<ion-list>
<ion-item>
<ion-input label-placement="stacked" label="Email" placeholder="email@domain.com">
<ion-icon slot="start" name="lock-closed" aria-hidden="true"></ion-icon>
<ion-button fill="clear" slot="end" aria-label="Show/hide">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-input>
</ion-item>
</ion-list>
</div>
</ion-content>
</ion-app>
</body>
</html>
17 changes: 17 additions & 0 deletions static/usage/v7/input/start-end-slots/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Playground from '@site/src/components/global/Playground';

import javascript from './javascript.md';
import react from './react.md';
import vue from './vue.md';
import angular from './angular.md';

<Playground
version="7"
code={{
javascript,
react,
vue,
angular,
}}
src="usage/v7/input/start-end-slots/demo.html"
/>
12 changes: 12 additions & 0 deletions static/usage/v7/input/start-end-slots/javascript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
```html
<ion-list>
<ion-item>
<ion-input label-placement="stacked" label="Email" placeholder="email@domain.com">
<ion-icon slot="start" name="lock-closed" aria-hidden="true"></ion-icon>
<ion-button fill="clear" slot="end" aria-label="Show/hide">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-input>
</ion-item>
</ion-list>
```
21 changes: 21 additions & 0 deletions static/usage/v7/input/start-end-slots/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
```tsx
import React from 'react';
import { IonButton, IonIcon, IonInput, IonItem, IonList } from '@ionic/react';
import { eye, lockClosed } from 'ionicons/icons';

function Example() {
return (
<IonList>
<IonItem>
<IonInput labelPlacement="stacked" label="Email" placeholder="email@domain.com">
<IonIcon slot="start" icon={lockClosed} aria-hidden="true"></IonIcon>
<IonButton fill="clear" slot="end" aria-label="Show/hide">
<IonIcon slot="icon-only" name={eye} aria-hidden="true"></IonIcon>
</IonButton>
</IonInput>
</IonItem>
</IonList>
);
}
export default Example;
```
33 changes: 33 additions & 0 deletions static/usage/v7/input/start-end-slots/vue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
```html
<template>
<ion-list>
<ion-item>
<ion-input label-placement="stacked" label="Email" placeholder="email@domain.com">
<ion-icon slot="start" :icon="lockClosed" aria-hidden="true"></ion-icon>
<ion-button fill="clear" slot="end" aria-label="Show/hide">
<ion-icon slot="icon-only" :icon="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-input>
</ion-item>
</ion-list>
</template>

<script lang="ts">
import { IonButton, IonIcon, IonInput, IonItem, IonList } from '@ionic/vue';
import { eye, lockClosed } from 'ionicons/icons';
import { defineComponent } from 'vue';

export default defineComponent({
components: {
IonButton,
IonIcon,
IonInput,
IonItem,
IonList,
},
setup() {
return { eye, lockClosed };
},
});
</script>
```
15 changes: 15 additions & 0 deletions static/usage/v7/select/start-end-slots/angular.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```html
<ion-list>
<ion-item>
<ion-select labelPlacement="stacked" label="Favorite fruit" value="apple">
<ion-icon slot="start" name="leaf" aria-hidden="true"></ion-icon>
<ion-select-option value="apple">Apple</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="orange">Orange</ion-select-option>
<ion-button fill="clear" slot="end" aria-label="Show/hide password">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-select>
</ion-item>
</ion-list>
```
45 changes: 45 additions & 0 deletions static/usage/v7/select/start-end-slots/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Select</title>
<link rel="stylesheet" href="../../../common.css" />
<script src="../../../common.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@7/dist/ionic/ionic.esm.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@7/css/ionic.bundle.css" />

<style>
/**
* This is to deal with a bug in 7.6 where a select in a list/item
* wrapped in a flex container will shrink to 0 width. When the bug
* is fixed, we can remove this.
*/
ion-list {
min-width: 400px;
}
</style>
</head>

<body>
<ion-app>
<ion-content>
<div class="container">
<ion-list>
<ion-item>
<ion-select label-placement="stacked" label="Favorite fruit" value="apple">
<ion-icon slot="start" name="leaf" aria-hidden="true"></ion-icon>
<ion-select-option value="apple">Apple</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="orange">Orange</ion-select-option>
<ion-button fill="clear" slot="end" aria-label="Show/hide password">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-select>
</ion-item>
</ion-list>
</div>
</ion-content>
</ion-app>
</body>
</html>
18 changes: 18 additions & 0 deletions static/usage/v7/select/start-end-slots/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Playground from '@site/src/components/global/Playground';

import javascript from './javascript.md';
import react from './react.md';
import vue from './vue.md';
import angular from './angular.md';

<Playground
version="7"
code={{
javascript,
react,
vue,
angular,
}}
src="usage/v7/select/start-end-slots/demo.html"
size="300px"
/>
15 changes: 15 additions & 0 deletions static/usage/v7/select/start-end-slots/javascript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```html
<ion-list>
<ion-item>
<ion-select label-placement="stacked" label="Favorite fruit" value="apple">
<ion-icon slot="start" name="leaf" aria-hidden="true"></ion-icon>
<ion-select-option value="apple">Apple</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="orange">Orange</ion-select-option>
<ion-button fill="clear" slot="end" aria-label="Show/hide password">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-select>
</ion-item>
</ion-list>
```
24 changes: 24 additions & 0 deletions static/usage/v7/select/start-end-slots/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
```tsx
import React from 'react';
import { IonButton, IonIcon, IonItem, IonList, IonSelect, IonSelectOption } from '@ionic/react';
import { eye, leaf } from 'ionicons/icons';

function Example() {
return (
<IonList>
<IonItem>
<IonSelect labelPlacement="stacked" label="Favorite fruit" value="apple">
<IonIcon slot="start" icon={leaf} aria-hidden="true"></IonIcon>
<IonSelectOption value="apple">Apple</IonSelectOption>
<IonSelectOption value="banana">Banana</IonSelectOption>
<IonSelectOption value="orange">Orange</IonSelectOption>
<IonButton fill="clear" slot="end" aria-label="Show/hide password">
<IonIcon slot="icon-only" icon={eye} aria-hidden="true"></IonIcon>
</IonButton>
</IonSelect>
</IonItem>
</IonList>
);
}
export default Example;
```
37 changes: 37 additions & 0 deletions static/usage/v7/select/start-end-slots/vue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
```html
<template>
<ion-list>
<ion-item>
<ion-select label-placement="stacked" label="Favorite fruit" value="apple">
<ion-icon slot="start" :icon="leaf" aria-hidden="true"></ion-icon>
<ion-select-option value="apple">Apple</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="orange">Orange</ion-select-option>
<ion-button fill="clear" slot="end" aria-label="Show/hide password">
<ion-icon slot="icon-only" :icon="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-select>
</ion-item>
</ion-list>
</template>

<script lang="ts">
import { IonButton, IonIcon, IonItem, IonList, IonSelect, IonSelectOption } from '@ionic/vue';
import { eye, leaf } from 'ionicons/icons';
import { defineComponent } from 'vue';

export default defineComponent({
components: {
IonButton,
IonIcon,
IonItem,
IonList,
IonSelect,
IonSelectOption,
},
setup() {
return { eye, leaf };
},
});
</script>
```
12 changes: 12 additions & 0 deletions static/usage/v7/textarea/start-end-slots/angular.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
```html
<ion-list>
<ion-item>
<ion-textarea labelPlacement="stacked" label="Comments" placeholder="Enter your comments">
<ion-icon slot="start" name="lock-closed" aria-hidden="true"></ion-icon>
<ion-button fill="clear" slot="end" aria-label="Show/hide">
<ion-icon slot="icon-only" name="eye" aria-hidden="true"></ion-icon>
</ion-button>
</ion-textarea>
</ion-item>
</ion-list>
```
Loading
Loading