Skip to content

Commit cd309cc

Browse files
docs(radio): add helperText and errorText section through radio-group (#4034)
Co-authored-by: Brandy Smith <[email protected]>
1 parent 65ef887 commit cd309cc

File tree

8 files changed

+298
-0
lines changed

8 files changed

+298
-0
lines changed

docs/api/radio.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ import EmptySelection from '@site/static/usage/v8/radio/empty-selection/index.md
7676

7777
<EmptySelection />
7878

79+
## Helper & Error Text
80+
81+
Helper and error text can be used inside of a radio group with the `helperText` and `errorText` property. The error text will not be displayed unless the `ion-invalid` and `ion-touched` classes are added to the `ion-radio-group`. This ensures errors are not shown before the user has a chance to enter data.
82+
83+
In Angular, this is done automatically through form validation. In JavaScript, React and Vue, the class needs to be manually added based on your own validation.
84+
85+
import HelperError from '@site/static/usage/v8/radio/helper-error/index.md';
86+
87+
<HelperError />
88+
7989

8090
## Theming
8191

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
```html
2+
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
3+
<ion-radio-group
4+
formControlName="favFruit"
5+
helperText="Select your favorite fruit"
6+
errorText="This field is required"
7+
>
8+
<ion-radio value="grapes">Grapes</ion-radio><br />
9+
<ion-radio value="strawberries">Strawberries</ion-radio><br />
10+
<ion-radio value="pineapple">Pineapple</ion-radio><br />
11+
<ion-radio value="cherries">Cherries</ion-radio>
12+
</ion-radio-group>
13+
14+
<br />
15+
16+
<ion-button type="submit" size="small">Submit</ion-button>
17+
</form>
18+
```
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
```ts
2+
import { Component } from '@angular/core';
3+
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
4+
import { IonRadioGroup, IonRadio, IonButton } from '@ionic/angular/standalone';
5+
6+
@Component({
7+
selector: 'app-example',
8+
standalone: true,
9+
imports: [IonRadioGroup, IonRadio, IonButton, ReactiveFormsModule],
10+
templateUrl: './example.component.html',
11+
styleUrl: './example.component.css',
12+
})
13+
export class ExampleComponent {
14+
myForm: FormGroup;
15+
16+
constructor(private fb: FormBuilder) {
17+
this.myForm = this.fb.group({
18+
favFruit: ['', Validators.required],
19+
});
20+
}
21+
22+
onSubmit() {
23+
// Mark the control as touched to trigger the error message.
24+
// This is needed if the user submits the form without interacting
25+
// with the toggle.
26+
this.myForm.get('favFruit')!.markAsTouched();
27+
}
28+
}
29+
```
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Input</title>
7+
<link rel="stylesheet" href="../../common.css" />
8+
<script src="../../common.js"></script>
9+
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@8/dist/ionic/ionic.esm.js"></script>
10+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@8/css/ionic.bundle.css" />
11+
12+
<style>
13+
ion-radio-group {
14+
display: inline-block;
15+
width: 200px;
16+
}
17+
</style>
18+
</head>
19+
20+
<body>
21+
<div class="container">
22+
<form id="my-form">
23+
<ion-radio-group helper-text="Select your favorite fruit" error-text="This field is required">
24+
<ion-radio value="grapes">Grapes</ion-radio><br />
25+
<ion-radio value="strawberries">Strawberries</ion-radio><br />
26+
<ion-radio value="pineapple">Pineapple</ion-radio><br />
27+
<ion-radio value="cherries">Cherries</ion-radio>
28+
</ion-radio-group>
29+
30+
<br />
31+
32+
<ion-button type="submit" size="small">Submit</ion-button>
33+
</form>
34+
</div>
35+
36+
<script>
37+
const form = document.getElementById('my-form');
38+
const favFruit = form.querySelector('ion-radio-group');
39+
40+
form.addEventListener('submit', (event) => submit(event));
41+
favFruit.addEventListener('ionChange', (event) => validateRadioGroup(event));
42+
43+
const validateRadioGroup = (event) => {
44+
favFruit.classList.add('ion-touched');
45+
46+
if (!event.detail.value) {
47+
favFruit.classList.add('ion-invalid');
48+
favFruit.classList.remove('ion-valid');
49+
} else {
50+
favFruit.classList.remove('ion-invalid');
51+
favFruit.classList.add('ion-valid');
52+
}
53+
};
54+
55+
const submit = (event) => {
56+
event.preventDefault();
57+
58+
validateRadioGroup({ detail: { value: favFruit.value } });
59+
};
60+
</script>
61+
</body>
62+
</html>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Playground from '@site/src/components/global/Playground';
2+
3+
import javascript from './javascript.md';
4+
import react from './react.md';
5+
import vue from './vue.md';
6+
7+
import angular_example_component_html from './angular/example_component_html.md';
8+
import angular_example_component_ts from './angular/example_component_ts.md';
9+
10+
<Playground
11+
version="8"
12+
code={{
13+
javascript,
14+
react,
15+
vue,
16+
angular: {
17+
files: {
18+
'src/app/example.component.html': angular_example_component_html,
19+
'src/app/example.component.ts': angular_example_component_ts,
20+
},
21+
},
22+
}}
23+
src="usage/v8/radio/helper-error/demo.html"
24+
/>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
```html
2+
<form id="my-form">
3+
<ion-radio-group helper-text="Select your favorite fruit" error-text="This field is required">
4+
<ion-radio value="grapes">Grapes</ion-radio><br />
5+
<ion-radio value="strawberries">Strawberries</ion-radio><br />
6+
<ion-radio value="pineapple">Pineapple</ion-radio><br />
7+
<ion-radio value="cherries">Cherries</ion-radio>
8+
</ion-radio-group>
9+
10+
<br />
11+
12+
<ion-button type="submit" size="small">Submit</ion-button>
13+
</form>
14+
15+
<script>
16+
const form = document.getElementById('my-form');
17+
const favFruit = form.querySelector('ion-radio-group');
18+
19+
form.addEventListener('submit', (event) => submit(event));
20+
favFruit.addEventListener('ionChange', (event) => validateRadioGroup(event));
21+
22+
const validateRadioGroup = (event) => {
23+
favFruit.classList.add('ion-touched');
24+
25+
if (!event.detail.value) {
26+
favFruit.classList.add('ion-invalid');
27+
favFruit.classList.remove('ion-valid');
28+
} else {
29+
favFruit.classList.remove('ion-invalid');
30+
favFruit.classList.add('ion-valid');
31+
}
32+
};
33+
34+
const submit = (event) => {
35+
event.preventDefault();
36+
37+
validateRadioGroup({ detail: { value: favFruit.value } });
38+
};
39+
</script>
40+
```
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
```tsx
2+
import React, { useRef, useState } from 'react';
3+
import { IonRadioGroup, IonRadio, IonButton, RadioGroupCustomEvent } from '@ionic/react';
4+
5+
function Example() {
6+
const [isTouched, setIsTouched] = useState<boolean>(false);
7+
const [isValid, setIsValid] = useState<boolean | undefined>();
8+
9+
const favFruitRef = useRef<HTMLIonRadioGroupElement>(null);
10+
11+
const validateRadioGroup = (event: RadioGroupCustomEvent<{ value: string }>) => {
12+
setIsTouched(true);
13+
setIsValid(event.detail.value ? true : false);
14+
};
15+
16+
const submit = (event: React.FormEvent<HTMLFormElement>) => {
17+
event.preventDefault();
18+
19+
if (favFruitRef.current) {
20+
validateRadioGroup({ detail: { value: favFruitRef.current.value } } as RadioGroupCustomEvent<{
21+
value: string;
22+
}>);
23+
}
24+
};
25+
26+
return (
27+
<>
28+
<form onSubmit={submit}>
29+
<IonRadioGroup
30+
ref={favFruitRef}
31+
className={`${isValid ? 'ion-valid' : ''} ${isValid === false ? 'ion-invalid' : ''} ${
32+
isTouched ? 'ion-touched' : ''
33+
}`}
34+
helperText="Select your favorite fruit"
35+
errorText="This field is required"
36+
onIonChange={(event) => validateRadioGroup(event)}
37+
>
38+
<IonRadio value="grapes">Grapes</IonRadio>
39+
<br />
40+
<IonRadio value="strawberries">Strawberries</IonRadio>
41+
<br />
42+
<IonRadio value="pineapple">Pineapple</IonRadio>
43+
<br />
44+
<IonRadio value="cherries">Cherries</IonRadio>
45+
</IonRadioGroup>
46+
47+
<br />
48+
49+
<IonButton type="submit" size="small">
50+
Submit
51+
</IonButton>
52+
</form>
53+
</>
54+
);
55+
}
56+
57+
export default Example;
58+
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
```html
2+
<template>
3+
<form @submit.prevent="submit">
4+
<ion-radio-group
5+
v-model="favFruit"
6+
helper-text="Select your favorite fruit"
7+
error-text="This field is required"
8+
@ionChange="validateRadioGroup"
9+
:class="{ 'ion-valid': isValid, 'ion-invalid': isValid === false, 'ion-touched': isTouched }"
10+
>
11+
<ion-radio value="grapes">Grapes</ion-radio><br />
12+
<ion-radio value="strawberries">Strawberries</ion-radio><br />
13+
<ion-radio value="pineapple">Pineapple</ion-radio><br />
14+
<ion-radio value="cherries">Cherries</ion-radio>
15+
</ion-radio-group>
16+
17+
<br />
18+
19+
<ion-button type="submit" size="small">Submit</ion-button>
20+
</form>
21+
</template>
22+
23+
<script lang="ts">
24+
import { defineComponent, ref } from 'vue';
25+
import { IonRadioGroup, IonRadio, IonButton, RadioGroupCustomEvent } from '@ionic/vue';
26+
27+
export default defineComponent({
28+
components: {
29+
IonRadioGroup,
30+
IonRadio,
31+
IonButton,
32+
},
33+
setup() {
34+
const favFruit = ref('');
35+
const isTouched = ref(false);
36+
const isValid = ref<boolean | undefined>();
37+
38+
const validateRadioGroup = (event: RadioGroupCustomEvent<{ value: string }>) => {
39+
isTouched.value = true;
40+
isValid.value = event.detail.value ? true : false;
41+
};
42+
43+
const submit = () => {
44+
validateRadioGroup({ detail: { value: favFruit.value } } as RadioGroupCustomEvent<{ value: string }>);
45+
};
46+
47+
return {
48+
favFruit,
49+
isTouched,
50+
isValid,
51+
validateRadioGroup,
52+
submit,
53+
};
54+
},
55+
});
56+
</script>
57+
```

0 commit comments

Comments
 (0)