Esikatselu
<Textarea />
Käyttötarkoitus
Textarea
tuottaa monirivisen tekstikentän, jota käytetään lomakkeissa, kun tarvitaan tekstikenttä pidemmän tekstisisällön syöttämiseen.
Komponentti tekee pelkän tekstikentän, joka yhdistetään InputGroup
, InputLabel
ja InputText
-komponenttien kanssa toimivan kokonaisuuden toteuttamiseksi.
Pyri ensisijaisesti käyttämään TextInput-komponenttia, jolla voit helposti tehdä saavutettavia kenttiä valmiilla ulkoasulla.
Textarea
-komponenttia kannattaa hyödyntää silloin kun TextInput
ei suoraan taivu toivottuun lopputulokseen.
- Älä käytä Textarea-komponenttia, jos tarvitset yksirivistä tekstikenttää. Käytä sen sijasta Input-komponenttia
Saavutettavuus
Muista huomioida ruudunlukijan käyttäjät, jos yhdistät kenttään virheilmoituksia ja ohjeita. Käytä silloin htmlFor
ja aria-describedby
-attribuuteja.
Esimerkit
Tekstikentän toteutus
<InputGroup>
<InputLabel htmlFor="myohastymisselvitys" requiredLabel="Pakollinen tieto">
Myöhästymisselvitys
</InputLabel>
<Row gx={2}>
<Column col={12} sm={12} md={10}>
<Textarea
id="myohastymisselvitys"
rows={5}
required
invalid
aria-describedby="myohastymisselvitys-error myohastymisselvitys-info"
/>
<InputText error id="myohastymisselvitys-error">
Virheilmoitustekstit esitetään kentän alapuolella.
</InputText>
<InputText info id="myohastymisselvitys-info" className="kds-mt-2">
Mahdollinen tekstikentän lisätieto.
</InputText>
</Column>
</Row>
</InputGroup>
Tekstikentän eri tilat
<>
<InputGroup>
<Textarea defaultValue="Tekstikenttä - normaali" />
</InputGroup>
<InputGroup>
<Textarea defaultValue="Tekstikenttä - readonly" readOnly />
</InputGroup>
<InputGroup>
<Textarea defaultValue="Tekstikenttä - disabled" disabled />
</InputGroup>
<InputGroup>
<Textarea defaultValue="Tekstikenttä - invalid" invalid />
</InputGroup>
</>
Tekstikentän koko
Tekstikentän automaattista kasvua saa rajoitettua antamalla komponentin autogrow
-propille arvon false
. Tällöin komponentille tulee vierityspalkki annetun rivimäärän ylittyessä.
<InputGroup>
<InputLabel htmlFor="demoTextArea">Otsikkokenttä</InputLabel>
<Row gx={2}>
<Column>
<Textarea id="demoTextArea" rows={5} aria-describedby="demoTextArea-info" />
<InputText info id="demoTextArea-info" className="kds-mt-2">
Kenttä kasvaa automaattisesti, kun siihen syötetään tekstiä.
</InputText>
</Column>
<Column>
<Textarea id="demoTextArea" rows={5} autogrow={false} aria-describedby="demoTextArea-info" />
<InputText info id="demoTextArea-info" className="kds-mt-2">
Kenttä ei kasva automaattisesti, mutta käyttäjä voi itse muuttaa kentän kokoa.
</InputText>
</Column>
</Row>
</InputGroup>
Merkkimäärälaskurin toteutus
Esimerkissä on huomioitu ruudunlukija siten, että merkkimäärä luetaan kahden sekunnin kuluttua siitä kun käyttäjä on lopettanut kirjoittamisen, jotta ruudunlukija ei lue liikaa tietoa.
Merkkimäärän ylittyminen luetaan heti ja myös rajan ylittävien merkkien määrä ilmoitetaan.
const useCharacterCounter = ({ delayAfterType, maxLength }: { delayAfterType: number; maxLength: number }) => {
const getCharCount = (value: string) =>
value.length > maxLength ? value.length - maxLength : maxLength - value.length;
const errorText = `Kenttään voi syöttää vain ${maxLength} merkkiä.`;
const timeout = useRef<ReturnType<typeof setTimeout>>();
const [value, setValue] = useState("");
const [charCount, setCharCount] = useState(getCharCount(value));
const [srCharCount, setSrCharCount] = useState(getCharCount(value));
const [isSrCharsOver, setIsSrCharsOver] = useState(value.length > maxLength);
const [isCharsOver, setIsCharsOver] = useState(value.length > maxLength);
const [error, setError] = useState(value.length > maxLength ? errorText : "");
const [isFocused, setIsFocused] = useState(false);
const handleOnChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setValue(e.target.value);
if (e.target.value.length > maxLength) {
setError(errorText);
setCharCount(getCharCount(e.target.value));
setIsCharsOver(true);
if (!isCharsOver) {
setIsSrCharsOver(true);
setSrCharCount(getCharCount(e.target.value));
clearTimeout(timeout.current);
}
} else {
setError("");
setCharCount(getCharCount(e.target.value));
setIsCharsOver(false);
if (isCharsOver) {
setSrCharCount(getCharCount(e.target.value));
setIsSrCharsOver(false);
}
}
clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
setSrCharCount(getCharCount(e.target.value));
setIsSrCharsOver(e.target.value.length > maxLength);
}, delayAfterType);
};
const handleOnFocus = (e: FocusEvent<HTMLTextAreaElement>) => {
setIsFocused(true);
setSrCharCount(getCharCount(e.target.value));
setTimeout(() => {
setIsFocused(false);
}, 300);
};
const handleOnBlur = (e: FocusEvent<HTMLTextAreaElement>) => {
setSrCharCount(getCharCount(e.target.value));
clearTimeout(timeout.current);
};
useEffect(() => {
return () => {
clearTimeout(timeout.current);
};
}, []);
return {
handleOnFocus,
handleOnBlur,
handleOnChange,
value,
error,
charCount,
srCharCount,
isCharsOver,
isSrCharsOver,
isFocused,
};
};
const ExampleTextareaCharCounter = () => {
const {
handleOnBlur,
handleOnChange,
handleOnFocus,
error,
isFocused,
isCharsOver,
isSrCharsOver,
srCharCount,
charCount,
value,
} = useCharacterCounter({ delayAfterType: 2000, maxLength: 400 });
return (
<InputGroup>
<InputLabel htmlFor="merkkimaaralaskuri" requiredLabel="Pakollinen tieto">
Merkkimäärälaskuri
</InputLabel>
<InputText id="merkkimaaralaskuri-help">
Merkkimäärä ilmoitetaan ruudunlukijalle kahden sekunnin kuluttua kirjoittamisen lopettamisesta.
</InputText>
<Row gx={2}>
<Column col={12} md={10}>
<Textarea
id="merkkimaaralaskuri"
rows={5}
required
invalid={!!error}
value={value}
onFocus={handleOnFocus}
onChange={handleOnChange}
onBlur={handleOnBlur}
aria-describedby={clsx(
{ "merkkimaaralaskuri-error": !!error },
"merkkimaaralaskuri-help merkkimaaralaskuri-counter"
)}
/>
{error && (
<InputText error id="merkkimaaralaskuri-error">
{error}
</InputText>
)}
<InputText info id="merkkimaaralaskuri-counter" className="kds-mt-2" aria-hidden={!isFocused}>
{isCharsOver && <span>{charCount} merkkiä yli sallitun määrän</span>}
{!isCharsOver && <span>{charCount} merkkiä jäljellä</span>}
</InputText>
<InputText info className="kds-sr-only" aria-live="assertive" aria-atomic="true">
{isSrCharsOver && <span>{srCharCount} merkkiä yli sallitun määrän</span>}
{!isSrCharsOver && <span>{srCharCount} merkkiä jäljellä</span>}
</InputText>
</Column>
</Row>
</InputGroup>
);
};
render(<ExampleTextareaCharCounter />);