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.
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="white" 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 />);