Esikatselu
<Chat>
<ChatMessage position="left">
<Text>Lorem ipsum</Text>
</ChatMessage>
</Chat>
Käyttötarkoitus
Käytä Chat-komponenttia, kun haluat viestiä asiakkaalle vuoropuhelumaisesti. Komponentti sopii tilanteisiin, joissa
halutaan edetä yksi asia tai kysymys kerrallaan. Komponenttia voi soveltaa esimerkiksi live-chatissa, chattirobotissa tai
kysymys kerrallaan etenevässä hakemusmallissa.
- Pidä viestit lyhyinä ja ytimekkäinä.
- Pitkät asiakokonaisuudet kannattaa jakaa useaan viestiin, jotka ilmestyvät peräkkäin pienellä viiveellä.
- Esitä tärkein asia ensin, mutta asiakkaalle esitetyt kysymykset aina viimeiseksi.
- Esitä sinisessä viestikuplassa vain tekstiä ja linkkejä.
- Käytä aina
loading
-proppia, jos viestin muodostamisessa on viivettä. - Esitä asiakkaan toiminnot ja vastaukset aina vaaleanharmaassa viestikuplassa.
- Älä laita yhteen viestikuplaan montaa eri asiaa.
- Älä käytä sinisessä viestikuplassa tekstin alleviivausta tai lihavointia.
Saavutettavuus
Navigointi chat-komponenttiin
Jos käytät chat-komponenttia live-chatissa tai chattirobotissa, muista varmistaa, että chat-ikkuna on löydettävissä sivulta nopeasti ja sen avaaminen ja sulkeminen on helppoa.
Tähän liittyen on hyvä huomioida muutamia asioita:
- oletuksena chat-ikkuna on kiinni
- jos chat-ikkuna sijaitsee dom-puun lopussa, sivun alkuun on lisättävä ohituslinkki
- myös maamerkki (role=“log”) autaa chat-ikkunan havaitsemista ja löytämistä
On suositeltava, että kirjoituskentästä pääsee siirtymään sulkemispainikkeeseen max. muutamalla tabin painalluksella. Avaamisen
tai sulkemisen jälkeen chat-ikkunan tilan on päivityttävä. Sulkemisen jälkeen fokus siirretään sivun alkuun tai muuhun loogiseen
paikkaan.
Chatin sisällön saavutettavuus
Chat-komponenttia käytettäessä pitää kiinnittää huomiota viestikuplien ja sisältöjen
saavutettavuuteen.
- Varmista, että sisältöä on mahdollista scrollata:
overflow-y: scroll
.
- Varmista, että chat-ikkunassa voi liikkua nuolinäppäimillä.
- Ruudunlukijan varassa chatia käytettävän käyttäjän on tärkeä saada tieto uuden viestin saapumisesta. Tämä onnistuu asettamalla
Chat
-komponentille aria-live
- ja aria-atomic
-attribuutit.
- Sininen viestikupla on tarkoitettu pääasiassa tekstille ja linkeille.
- Muut sisällöt, kuten taulukot, tulee laittaa valkoiseen viestikuplaan sinisen viestin yhteyteen.
- Vaaleanharmaisiin viestikupliin voi laittaa sisältöjä laajemmin, esim. lomake-elementtejä, mutta näissäkin tulee varmistaa, että saavutettavuusvaatimukset toteutuvat, mm.:
- kontrastivaatimukset täyttyvät
- kaikilla interaktiivisilla elementeilla on
label
/ aria-label
-attribuutit
- kuvilla on
alt
-attribuutit
- Sinisen viestikuplan linkit alleviivataan automaattisesti. Älä siis käytä tekstin alleviivausta korostamaan tekstiä sinisessä viestikuplassa.
Viestikentässä olevien kenttien ryhmittely
Chat-muotoisissa käyttöliittymissä sijaitsevien valintaryhmien rakenne:
role="group"
sisältää valinnat ja yhdistää ne ryhmäksi.
- kysymys tai ohjeistus on erillinen elementti, johon viitataan
aria-labelledby
-attribuutilla.
- valintapainikeet on sijoitettu loogisesti ja käyttäjän on helppo navigoida niihin.
<Chat>
<ChatMessage position="left" animate={false} id="form-id">
<Text>Asuuko perheessäsi kotieläimiä?</Text>
</ChatMessage>
<ChatMessage position="right" animate={false} form>
<div role="group" className="kds-mb-6" aria-labelledby="form-id">
<Radio name="chat-form-example" labelText="Kyllä" />
<Radio name="chat-form-example" labelText="Ei" />
</div>
<Button>Jatka</Button>
</ChatMessage>
</Chat>
Esimerkit
Väri ja asettelu
Kelan ja Kannan viestit
Kelan ja Kannan viestit (esim. chattirobotti, hakemusavustaja ym.) esitetään aina keskusteluketjun
vasemmassa reunassa sinisellä taustavärillä.
Viestikuplille on suositeltavaa antaa name
-propilla viestijän nimi tai rooli, sekä aikaleima.
<Chat>
<ChatMessage position="left" animate={false} name="Chattirobotti 14.30">
<Text>
Hei! Olen Kelan chattirobotti. Neuvon sinua kysymyksissä, jotka liittyvät lastenhoidon tukiin,
vanhempainpäivärahoihin, äitiysavustukseen, lapsilisään ja elatustukeen. Opettelen näitä asioita vasta, joten en
välttämättä osaa vastata ihan kaikkeen.
</Text>
<Text>Ethän kirjoita chattiin henkilötietojasi tietoturvasyistä.</Text>
<Text>
Miten voin auttaa? Ymmärrän parhaiten lyhyitä ja selkeitä kysymyksiä, esimerkiksi "Milloin isyysrahahakemus on
tehtävä?"
</Text>
</ChatMessage>
</Chat>
Valkopohjainen viestikupla
Mikäli Kelan ja Kannan viestissä on tarve esittää tekstin lisäksi muuta lisätietoa, kuten
taulukoita tai muita komponentteja, lisää lisätieto omaan valkopohjaiseen viestikuplaan
käyttämällä outline
-propia.
Käytä valkopohjaista viestikuplaa:
- Pohjatietojen näyttämiseen.
- Sinipohjaisen kysymyskuplan yläpuolella selventämään kysymystä.
- Toimintaohjeena, kun asiakkaalle näytetään lisätietoa hänen antamastaan vastauksesta.
Kirjoita lyhyitä tekstejä. Osan teksteistä voi piilottaa Accordion
-komponentin avulla.
Vuoropuhelun pohjatiedot
Voit käyttää valkopohjaista viestikuplaa pohjatietojen näyttämiseen.
<Chat>
<ChatMessage position="left" outline>
<Text mb={0}>Kela saa seuraavat tiedot väestörekisteristä:</Text>
<Text mb={2}>Lasten syntymäajat</Text>
<List>
<ListItem>5.3.2007</ListItem>
<ListItem>10.1.2009</ListItem>
<ListItem>31.1.2019</ListItem>
</List>
<Text>
Jos sinulla on muita alaikäisiä lapsia, joista olet elatusvelvollinen, lisää heidän tietonsa hakemukseen.
</Text>
</ChatMessage>
<ChatMessage position="right">
<ButtonGroup horizontal>
<Button>Jatka</Button>
<Button appearance="outline" iconBefore={<IconPlus />}>
Lisää lapsi
</Button>
</ButtonGroup>
</ChatMessage>
</Chat>
Kysymyksen selventäminen
Voit alustaa tai selventää valkopohjaisessa viestikuplassa sinisen kuplan kysymystä.
Voit piilottaa osan teksteistä Accordion
-komponentin avulla. Käytä Chat
-kuplassa Accordion
-komponenttia, kevyt haitarielementti linkkipainikkeen tyylillä.
const ChatExample = () => {
const [isOpen, setOpen] = useState(false);
return (
<Chat>
<ChatMessage position="left" outline>
<Text mb={2}>Asumistuen määrään vaikuttavat virtuaalivaluuttana saadut tulot.</Text>
<Accordion id="virtuaalivaluutta" isOpen={isOpen} appearance="link">
<AccordionToggle onClick={() => setOpen(!isOpen)}>Mitä on virtuaalivaluutta?</AccordionToggle>
<AccordionBody>
<Text>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros
ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu.
</Text>
<List>
<ListItem>Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit.</ListItem>
<ListItem>Sed augue orci, lacinia eu tincidunt et eleifend nec lacus.</ListItem>
<ListItem>Donec ultricies nisl ut felis, suspendisse potenti.</ListItem>
</List>
</AccordionBody>
</Accordion>
</ChatMessage>
<ChatMessage position="left">
<Text>Saatko virtuaalivaluutan louhinnasta tuloja?</Text>
</ChatMessage>
<ChatMessage position="right">
<InputGroup>
<Radio name="radio" labelText="Kyllä" value="default" />
<Radio name="radio" labelText="En saa" value="default" />
</InputGroup>
<ButtonGroup horizontal>
<Button>Jatka</Button>
<Button appearance="outline">Palaa</Button>
</ButtonGroup>
</ChatMessage>
</Chat>
);
};
render(<ChatExample />);
Vuoropuhelun aloitus
Voit käyttää valkopohjaista viestikuplaa vuoropuhelun aloituksena.
<Chat>
<ChatMessage position="left" outline>
<Heading as="h3" className="kds-mt-0">
Tervetuloa!
</Heading>
<Text>
<strong>Ennen kuin aloitat, huomoi seuraavat asiat:</strong>
</Text>
<List>
<ListItem>Pakolliset tiedot on merkitty *-merkillä.</ListItem>
<ListItem>
Siirry kysymyksestä toiseen 30 minuutin kuluessa. Jos et jatka hakemuksen täyttämistä, sinut kirjataan ulos
tieitoturvan varmistamiseksi.
</ListItem>
<ListItem>Voit kysyä apua chattirobotti Kela-Kelpolta.</ListItem>
<ListItem>
Jos olet työsuhteessa, selvitä enennen hakemuksen täyttämistä, maksaako työnantajasi sinulle palkkaa
perhevapaiden ajalta. Selvitä myös työnantajasi puhelinnumero.
</ListItem>
</List>
</ChatMessage>
<ChatMessage position="right">
<ButtonGroup horizontal>
<Button>Jatka</Button>
<Button appearance="outline">Palaa</Button>
</ButtonGroup>
</ChatMessage>
</Chat>
Toimintaohje
Voit antaa valkoisessa kuplassa asiakkaan vastaukseen liittyvää palautetta ja toimintaohjeita.
<Chat>
<ChatMessage position="left">
<Text>Haetko vanhempainrahaa?*</Text>
<Text>Vastaa Kyllä myös silloin, jos haet vanhempainrahaa osittaisena.</Text>
</ChatMessage>
<ChatMessage position="right">
<InputGroup>
<Text mb={2}>En</Text>
<Button appearance="link" iconBefore={<IconEdit />}>
Muokkaa
</Button>
</InputGroup>
</ChatMessage>
<ChatMessage position="left" outline>
<Text>Voit palata hakemaan vanhempainrahaa myöhemmin, jos muutat mielesi.</Text>
<Text>
Hae etuutta 2 kuukauden kuluessa valitsemastasi vanhempainrahan alkamispäivästä. vanhempainrahapäiviä voi käyttää
siihen asti, kun lapsi täyttää 2 vuotta tai adoptiolapsen hoitoonottopäivästä on kulunut 2 vuotta.
</Text>
</ChatMessage>
<ChatMessage position="right">
<ButtonGroup horizontal>
<Button>Jatka</Button>
<Button appearance="outline">Palaa</Button>
</ButtonGroup>
</ChatMessage>
</Chat>
Yhteenvetonäkymä
Komponentin ulkoasun voi määrittää vapaammin position
, variant
ja outline
ja rounded
-proppien yhdistelmillä, kun sitä käytetään normaalin Chat-toiminnallisuuden ulkopuolella, esimerkiksi Chat-muotoisen hakemuksen yhteenvetonäkymässä.
<div>
<Text mb={2}>
<strong>Mikä seuraavista vaihtoehdoista kuvaa tilannettasi 1.4.2024 alkaen?</strong>
</Text>
<InputGroup>
<Text mb={2}>Palkansaaja, kokopäivä- tai osa-aikatyö</Text>
<Button appearance="link" iconBefore={<IconEdit />}>
Muokkaa
</Button>
</InputGroup>
<Text>
<strong>Kuinka paljon arviosi mukaan saat palkkaa kuukaudessa 1.4.2024 alkaen?</strong>
</Text>
<Chat>
<ChatMessage variant="neutral" rounded position="left">
<Heading as="h3" mt={2}>
Työnantaja 1
</Heading>
<Text mb={2}>
<strong>Työnantajan nimi</strong>
</Text>
<Text>Yritys OY</Text>
<Text mb={2}>
<strong>Arvio palkan määrästä kuukaudessa 1.4.2024 alkaen</strong>
</Text>
<Text>1 300 euroa/kk</Text>
<Text mb={2}>
<strong>Onko kyseessä uusi työsuhde?</strong>
</Text>
<Text>Ei</Text>
<Button appearance="link" iconBefore={<IconEdit />}>
Muokkaa
</Button>
</ChatMessage>
</Chat>
<InputGroup className="kds-mt-4">
<Button appearance="outline" iconBefore={<IconPlus />}>
Lisää työnantaja
</Button>
</InputGroup>
</div>
Asiakkaan viestit
Asiakkaan viestit esitetään aina keskusteluketjun oikealla puolella vaaleanharmaissa viestikuplissa.
Jos asiakasta pyydetään vastaamaan kysymyksiin painikkeilla tai täyttämällä lomake-elementtejä, ne tulee esittää aina
asiakkaan viestikuplassa, viestiketjun oikealla puolella.
Jos sisältönä on muutakin, kuin teksti, on huomioitava, että:
- kuvilla on alt-atribuutti
- interaktiivisilla elementeilla on labelit / aria-labelit
<Chat>
<ChatMessage position="left" animate={false} name="Chattirobotti 14.33">
<Text>
Hei! Olen Kelan chattirobotti. Neuvon sinua kysymyksissä, jotka liittyvät lastenhoidon tukiin,
vanhempainpäivärahoihin, äitiysavustukseen, lapsilisään ja elatustukeen. Opettelen näitä asioita vasta, joten en
välttämättä osaa vastata ihan kaikkeen.
</Text>
<Text>Ethän kirjoita chattiin henkilötietojasi tietoturvasyistä.</Text>
<Text>
Miten voin auttaa? Ymmärrän parhaiten lyhyitä ja selkeitä kysymyksiä, esimerkiksi "Milloin isyysrahahakemus on
tehtävä?"
</Text>
</ChatMessage>
<ChatMessage position="right" animate={false} name="Minä 14.34">
<Text>Milloin isyysrahahakemus on tehtävä?</Text>
</ChatMessage>
</Chat>
Viestien lataaminen
Jos viestin sisällön muodostamisessa on viivettä, käytä loading
-propia antamaan
asiakkaalle palautetta sisällön latauksesta ja viestiketjun etenemisestä.
<Chat>
<ChatMessage position="left" animate={false} name="Chattirobotti 14.35">
<Text>
Hei! Olen Kelan chattirobotti. Neuvon sinua kysymyksissä, jotka liittyvät lastenhoidon tukiin,
vanhempainpäivärahoihin, äitiysavustukseen, lapsilisään ja elatustukeen. Opettelen näitä asioita vasta, joten en
välttämättä osaa vastata ihan kaikkeen.
</Text>
<Text>Ethän kirjoita chattiin henkilötietojasi tietoturvasyistä.</Text>
<Text>
Miten voin auttaa? Ymmärrän parhaiten lyhyitä ja selkeitä kysymyksiä, esimerkiksi "Milloin isyysrahahakemus on
tehtävä?"
</Text>
</ChatMessage>
<ChatMessage position="right" animate={false} name="Minä 14.36">
<Text>Milloin isyysrahahakemus on tehtävä?</Text>
</ChatMessage>
<ChatMessage position="left" loading name="Chattirobotti miettii..." />
</Chat>
Koko
Viestin koko ja viestien välinen tyhjä tila skaalautuu automaattisesti pienille näytöille.
Lisää viestille form
-prop, jos viesti sisältää tekstin lisäksi muita komponentteja, kuten taulukoita, painikkeita tai
lomake-elementtejä. Tämä lisää viestiin hieman enemmän paddingia ja se on helpompi lukea.
<Chat>
<ChatMessage position="right" animate={false} name="Minä 14.37">
<Text>Tässä viestissä on vain tekstiä</Text>
</ChatMessage>
<ChatMessage position="right" animate={false} form name="Minä 14.38">
<SelectionGroup className="kds-mb-6">
<Radio name="use-date" labelText="Kyllä" />
<Radio name="use-date" labelText="En, valitsen haettavan ajan" />
</SelectionGroup>
<Button>Tallenna</Button>
</ChatMessage>
</Chat>
Ilmoitus viestikuplassa
Viestikuplassa sijaitsevan ilmoituksen voi muuttaa valkoiseksi ja sen sisällölle saa enemmän tilaa sijoittamalla ikonin tekstin yläpuolelle.
Ilmoitusta voi myös tiivistää size
-propin tarjoamilla kokovaihtoehdoilla.
<Chat>
<ChatMessage position="left" animate={false}>
<Text>Haluatko lisätä liiteen? Voit ohittaa lisäämisen painamalla Jatka-painiketta.</Text>
</ChatMessage>
<ChatMessage position="right" animate={false} name="Minä 14.34">
<Alert variant="danger" bgColor="background" size="md" className="kds-mb-4" iconPosition="top">
<Text mb={1}>
Liitteen lisääminen ei onnistunut.
<br />
Tiedoston tyyppi ei ole sallittu:
</Text>
<List>
<ListItem>
<Link href="#">vuokrasopimus.heic</Link>
</ListItem>
</List>
</Alert>
<ButtonGroup horizontal="sm" className="kds-justify-end">
<Button variant="primary">Jatka</Button>
<Button variant="primary" apperance="outline" iconBefore={<IconPlus />}>
Lisää liite
</Button>
</ButtonGroup>
</ChatMessage>
</Chat>
Animaatio
ChatMessage
-komponentti on animoitu kiinnittämään asiakkaan huomiota uusiin
viesteihin ja korostamaan esitystavan keskustelumaisuutta. Mount-animaation voi
poistaa animate
-propilla, jos viestejä tulee kerralla useita, esimerkiksi kun viestejä
sisältävä näkymä ladataan ensimmäisen kerran.
Alla on yksinkertainen esimerkkitoteutus, joka esittelee animaation toimintaa.
const ChatBubble = ({ index, onMount, onLoaded, ...attrs }) => {
const [isLoading, setIsLoading] = useState(true);
const isEven = index % 2;
const timer = useRef();
useEffect(() => {
if (isLoading) {
timer.current = setTimeout(
() => {
setIsLoading(false);
},
Math.round(Math.random() * (2000 - 500) + 500)
);
return () => clearTimeout(timer.current);
}
}, []);
return (
<ChatMessage
name={isEven ? `Minä ${new Date().toLocaleTimeString()}` : `Chat ${new Date().toLocaleTimeString()}`}
loading={isLoading}
form={isEven ? true : false}
position={isEven ? "right" : "left"}
onMount={() => onMount()}
onLoaded={() => onLoaded()}
{...attrs}
>
{isEven ? (
<>
<InputGroup>
<Select defaultValue={0} aria-label="Valitse vuokranantaja">
<option value="0">Valitse vuokranantaja</option>
<option value="1">Vuokranantaja 1</option>
<option value="2">Vuokranantaja 2</option>
<option value="3">Vuokranantaja 3</option>
</Select>
</InputGroup>
<InputGroup>
<Checkbox labelText="Muu vuokranantaja" />
</InputGroup>
<Button>Tallenna</Button>
</>
) : (
<Text>Valitse vuokranantaja. Mikäli vuokranantajaasi ei löydy listalta, valitse muu vuokranantaja.</Text>
)}
</ChatMessage>
);
};
const ExampleChat = (props) => {
const [messages, setMessages] = useState([]);
const counter = useRef(0);
const chatContainer = useRef();
const reset = (msg) => {
setMessages([]);
counter.current = 0;
};
const add = () => {
counter.current += 1;
setMessages([counter.current, ...messages]);
};
const remove = () => {
counter.current -= 1;
setMessages(messages.slice(0, counter.current));
};
const updateScroll = () => {
if (chatContainer.current) {
chatContainer.current.scrollTop = chatContainer.current.scrollHeight;
}
};
return (
<>
<Chat
className="kds-p-2"
ref={chatContainer}
role="log"
aria-live="polite"
aria-atomic="false"
style={{ height: "500px", overflowY: "auto" }}
>
{messages.map((message, index) => (
<ChatBubble
index={index}
key={`message-${index}`}
onMount={() => updateScroll()}
onLoaded={() => updateScroll()}
/>
))}
</Chat>
<ButtonGroup horizontal="sm">
<Button appearance="outline" onClick={add}>
Lisää viesti
</Button>
<Button variant="danger" appearance="outline" onClick={remove}>
Poista viesti
</Button>
<Button variant="danger" appearance="outline" onClick={reset}>
Tyhjennä
</Button>
</ButtonGroup>
</>
);
};
render(<ExampleChat />);