This project hosts the JavaScript chat widget that connects customers using a web portal, to stores and associates using the Tulip LiveConnect on iOS. This feature is known as LiveConnect Web Chat.
This widget can be installed either via npm
, using Google Tag Manager, or linked in HTML.
Include the package in your project using npm
:
npm i @tulipnpm/livechat@latest
Many e-commerce websites use Google Tag Manager to inject third-party JavaScript into their pages. This is the recommended distribution method of LiveConnect Web Chat.
- Open Google Tag Manager and select the e-commerce site's account.
- Create a new Tag of type Custom HTML.
- Paste the following code in the tag. Replace <INTEGRATION_ID> with your integration ID. Additional configurations can be made in the
tlc_config
object. To view the configuration list and instructions, refer to the Web Chat Configurations page.
<script src="https://cdn.jsdelivr.net/npm/@tulipnpm/livechat@latest/dist/tuliplivechat.min.js"></script>
<script>
var tlc_config = {
integrationId: '<INTEGRATION_ID>'
};
tuliplivechat.init(tlc_config);
</script>
- Create a Trigger for DOM Ready and link it to your Tag.
- Name and save the Tag. You can then preview and publish your changes.
This completes the setup process using Google Tag Manager.
Include Web Chat directly in the HTML of your web site.
<script src="https://cdn.jsdelivr.net/npm/@tulipnpm/livechat@latest/dist/tuliplivechat.min.js"></script>
Initiate Web Chat with a configuration:
var tlc = tuliplivechat;
tlc.init({
integrationId: '<INTEGRATION_ID>'
}).then(() => {
// After init code goes here
});
Configuration options are provided when inititalizing the widget with init({..})
The integrationId
is also a configuration value. This value identifies your widget to Tulip. Tulip will provide you with this value when you purchase Tulip LiveConnect Web Chat.
This is an example configuration:
var tlc = tuliplivechat;
var config = {
integrationId: '<INTEGRATION_ID>',
displayStyle: 'button',
imageUploadEnabled: true,
fixedIntroPane: false,
buttonIconUrl: 'https://retailer.com/logo.png',
buttonWidth: '58px',
buttonHeight: '58px',
businessName: 'Retailer',
businessIconUrl: 'https://retailer.com/logo.png',
customColors: {
brandColor: 'ee3d50',
conversationColor: '151043',
actionColor: '333333',
contactUsButtonColor: '452BD6'
},
contactUsButtonUrl: 'https://retailer.com/contact',
};
tlc.init(config);
LiveConnect Web Chat has many configuration options:
Option | Optional? | Default value | Description |
---|---|---|---|
afterLoadCallback | Yes | A method that can be run after the initialization of a widget | |
awayMode | Yes | See details below | Controls the behaviour when an associate is unresponsive to a customer |
availabilityConfigurations | Yes | See details below | |
browserStorage | Yes | localStorage | See details below. Controls the longevity of the users session. Options are either localStorage or sessionStorage |
businessIconUrl | Yes | A custom business icon url. The image must be at least 200 x 200 pixels and must be in either JPG, PNG, or GIF format. | |
businessName | Yes | A custom business name | |
buttonHeight | Yes | 58px | When the displayStyle is button, you have the option of specifying the button height. |
buttonIconUrl | Yes | When the displayStyle is button, you have the option of selecting your own button icon. The image must be at least 200 x 200 pixels and must be in either JPG, PNG, or GIF format. | |
buttonWidth | Yes | 58px | When the displayStyle is button, you have the option of specifying the button width. |
contactUsButtonUrl | Yes | Link to a Contact Us page | |
cssOverwritePath | Yes | Path to a CSS file that can be applied to the chat window and widget. See below for details | |
customColors | Yes | See detail below | Colors used in the LiveConnect Web Chat UI. |
customText | Yes | See details below | Language and text used in the LiveConnect Web Chat UI. |
displayStyle | Yes | button | Choose how the widget will appear on your website. Must be either 'button' or 'tab'. When tab selected, it’ll appear as a pane at the bottom. |
embedded | Yes | false | See details below |
fallbackLanguageCode | Yes | en-US | See details below |
fixedIntroPane | Yes | false | When enabled, the introduction pane will be pinned at the top of the conversation instead of scrolling with it |
imageUploadEnabled | Yes | true | Enables the image upload feature. (deprecated: use menuItems.imageUpload; if this option is false, it will disable menuIt ems.imageUpload and menuItems.fileUpload) |
integrationOrder | No | Order of third party integrations to connect to during away mode. Speak to Tulip to get the identifiers for each integration | |
pageReferenceImageSelector | No | See details below. | |
prechatCapture | Yes | See detail below | Enables automatically capturing a user's name and email via a form before the start of a conversation. Disables the chat input until the form has been submitted. |
region | Yes | undefined | If your Tulip environment is hosted in the EU, set this value to 'eu-1' |
saveOpenState | Yes | true | When enabled, will open or close the chat window based on the state of the chat window on the previous page |
soundNotificationEnabled | Yes | false | When enabled, plays a notification sound when the user recieves a message |
supportedLanguages | Yes | All supported languages | See details below |
useGeolocation | Yes | false | When set to true, the user will be asked to share their location for Geolocation Routing. |
userCanDeleteSentMessages | Yes | false | When set to true, allows the user to delete their sent messages. See details below. |
Option | Optional? | Default value | Description |
---|---|---|---|
brandColor | Yes | ee3d50 | This color will be used in the messenger header and the button or tab in idle state. Must be a 3 or 6-character hexadecimal color. |
conversationColor | Yes | 151043 | This color will be used for customer messages, quick replies and actions in the footer. Must be a 3 or 6-character hexadecimal color. |
actionColor | Yes | 333333 | This color will be used for call-to-actions inside your messages. Must be a 3 or 6-character hexadecimal color. |
Prechat Capture allows you to capture a user’s data, like name and email, before the start of a conversation.
When configured, the chat input is initially disabled and the user is greeted by a welcome message and a form asking for their name.
Once the form is successfully submitted, a thank you message is sent to the user and the conversation is then initialized, connecting the user to your business.
Option | Description |
---|---|
prechatCaptureGreetingText | Text for the initial greeting message. |
prechatCaptureNameLabel | Label displayed for the default form's first field. |
prechatCaptureNamePlaceholder | Placeholder for the default form's first field. |
prechatCaptureEmailLabel | Label displayed for the default form's second field. |
prechatCaptureEmailPlaceholder | Placeholder for the default form's second field. |
prechatCaptureConfirmationText | Text for the confirmation message sent when the form is completed. |
prechatCaptureMailgunLinkingConfirmation | Text for the notification message when a user has linked their email address. |
Options in prechatCapture
Option | Optional? | Default value | Description |
---|---|---|---|
enabled | Yes | true | Enables the prechat capture experience. |
fields | Yes | Overrides the default Prechat Capture fields. |
Configuration for prechatCapture.fields
Arguments | Optional? | Description |
---|---|---|
type | No | Specifies the type of field. Options are text, email, select |
name | No | Specifies the name of the field. Each field name must be unique per form. Maximum length of 128 characters. |
label | No | Specifies what label the field will be displayed with. Maximum length of 128 characters. |
placeholder | Yes | Specifies the placeholder text of the field that will be rendered. Maximum length of 128 characters. |
minSize | Yes | Text field only. Specifies the minimum possible length of the response. Defaults to 1 if not specified. |
maxSize | Yes | Text field only. Specifies the maximum possible length of the response. Defaults to 128 if not specified. |
options | Yes | Select field only. Array of option objects (see below) that can be selected. The array is limited to 20 options. |
config.prechatCapture: {
enabled: true,
enableEmailLinking: true,
fields: [{
type: 'email',
name: 'email',
label: 'prechatCaptureEmailLabel',
placeholder: 'prechatCaptureEmailPlaceholder',
}, {
type: 'text',
name: 'name',
label: 'prechatCaptureNameLabel',
placeholder: 'prechatCaptureNamePlaceholder',
}, {
type: 'select',
name: 'country',
label: 'prechatCaptureCountryLabel',
placeholder: 'prechatCaptureCountryPlaceholder',
options: [
{
name: 'us',
label: 'United States',
},
{
name: 'ca',
label: 'Canada',
},
],
}]
}
In order to override the text that you set in a prechatCapture configuration, you must have a customText configuration as well. Please see the String Customization section for more details here. The value of the label or placeholder must match the key of whatever is in the customText configuration for it to change.
For example: if you wanted to change the name
object in the fields list of a prechatCapture config and you wanted to customize the label
's text in two different languages, you would have an additional config that would look like:
config.customText: {
'en-US': {
prechatCaptureNameLabel: 'this is an overridden name label',
},
'fr': {
prechatCaptureNameLabel: 'ceci est une étiquette de nom remplacée',
}
}
Please note that the key prechatCaptureLabel
is the same as the value in the config.preCapture object for the name
label. If they do not match, it will display the text of whatever the value is in the prechatCapture object. If they match, then the text will be customized based on what language the user is in.
{
enabled: true,
fields: [{
type: 'text',
name: 'name',
label: 'prechatCaptureNameLabel',
placeholder: 'prechatCaptureNamePlaceholder'
}]
}
If you do not want to use the default Tulip Prechat Capture form, you have the ability to capture your user's information before initializing the widget. All that is required to bypass the default Prechat Capture form is setting the firstName property on the user object. To do this, you can use the following methods.
Changes made to the user properies after initializing the widget will be applied on the application after the user sends their next message.
Asks as a bulk setting method for the user object. Takes an object with the keys being the property names and sets the object properties to their respective values. The only required field from this list will be firstName in order to bypass the default Prechat capture form.
tuliplivechat.setUser({
firstName: 'Thomas',
lastName: 'Hanks',
email: 'thomas.hanks@movie.ca',
firstOutboundMessage: 'Hello, I am looking for a bag, do you know where I can find one?'
});
Sets the user firstOutboundMessage property. This must be done before the widget is initialized. If this value is set, we will send a message to the application on behalf of the user.
tuliplivechat.setFirstOutboundMessage('Hello, I am looking for a bag, do you know where I can find one?');
Sends the first outbound message set to the application on behalf of the customer. This must be done after the widget is initialized and will not send if there has already been a message sent from the user to the application.
tuliplivechat.init({...}).then(() => {
tuliplivechat.setFirstOutboundMessage('Hello, I am looking for a bag, do you know where I can find one?');
tuliplivechat.sendFirstOutboundMessage();
})
When enabled, away mode will display a message to the user informing them that there are no associates able to chat currently after a certain period of time without a response. Away mode takes in two object arguements: pooledConversations and assignedConversations. The split in configurations is to allow for different behaviour between conversations that are assigned to an associate and ones that have not been accepted by anyone.
The customer can also be prompted to transfer the conversation to a third party integration. This will allow the conversation to continue off of the web chat. If a conversation is switched to a third party channel, the away messages will not be sent.
Option | Optional? | Default value | Description |
---|---|---|---|
enabled | Yes | false | When enabled, will turn on away mode polling. |
unresponsiveTime | Yes | null | Number of seconds without a message from an associate before showing the away mode message for conversations. |
showChannelSwitchPrompts | Yes | true | Controls whether to show the prompt to move conversation to a third party channel or not. |
awayMode: {
pooledConversations: {
enabled: true,
unresponsiveTime: 60,
showChannelSwitchPrompt: true
},
assignedConversations: {
enabled: true,
unresponsiveTime: 600,
showChannelSwitchPrompt: false
}
}
By default, LiveConnect Web Chat will store the identity of users in the localStorage
of the browser. Using localStorage
will persist the user identity throughout browser sessions (including page reloads and browser restarts).
To clear the user identity once the browser is closed, use sessionStorage
instead. Learn more.
To activate the embedded
mode, simply call the embed
method after running your init function with the embedded
configuration set to true. This method accepts the DOM ID of the element which will be used as the container where the widget will be rendered. The embedded widget will take full width and height of the container.
tuliplivechat.init({
integrationId: '<integration-id>',
embedded: true
});
tuliplivechat.embed('chat-container');
To apply your own custom CSS to our default elements, we allow for passing in a URL to a hosted CSS file using the cssOverwritePath
configuration. This CSS file will be added to the styles used on the widget as well as the chat window. Changes to the styling can be made by using the classes and IDs on the HTML elements that already exist and modifiying the properties.
For example, if you wanted to make the chat window have no border radius you could apply the following to your hosted CSS file.
#container #wrapper {
border-radius: 0px !important;
}
Opens the conversation widget. This method takes an optional boolean parameter. If the parameter is true, we will open the chat window and if it is false, we will close the chat window.
tuliplivechat.openChatWindow();
tuliplivechat.openChatWindow(true);
tuliplivechat.openChatWindow(false);
Closes the conversation widget.
tuliplivechat.closeChatWindow();
Removes the chat widget from the DOM. Will need to be re-initalizated if needed again.
tuliplivechat.removeChatWidget();
Hides the chat widget from the DOM by changing the display on #web-messenger-container
.
tuliplivechat.hideChatBubble();
Shows the chat widget to the DOM by changing the display on #web-messenger-container
to block. Does not make the chat widget appear after running removeChatWidget
. This method takes an optional boolean parameter. If the parameter is true, we will show the chat bubble and if it is false, we will hide the chat bubble.
tuliplivechat.showChatBubble();
tuliplivechat.showChatBubble(true);
tuliplivechat.showChatBubble(false);
Returns a boolean whether the current conversation is active or not. When run before the init
method, this method checks localStorage and sessionStorage for an existing conversation, as well as if it is ended or not.
tuliplivechat.isConversationActive();
Takes in an object of CSS key to value pairs and applies the styles to the chat window.
tuliplivechat.setChatWindowStyle({
'height': '90%',
'padding-left': '10%'
});
Use this method for checking available associates in your region. The availabilityConfigurations
option has to be set in config before using the method. The chat widget should have access to geolocation definition otherwise it returns an error. The method returns a promise and gives opportunity to do some actions after getting a result.
config.availabilityConfigurations: {
project: '<PROJECT_DOMAIN>',
apiKey: '<AVAILABILITY_AUTH_TOKEN>'
};
tuliplivechat.checkForAvailableAssociates().then((result) => {
// do some code
}).catch((error) => {
// do some code
});
The method can also be set by passing your project domain and availability auth token as parameters. An optional third parameter allows for the widget to continue or stop checking if no location exists. By default, this is set to true meaning it will continue with checking for available associates if no location exists. For example, a location would not exist if the user were to deny location permissions from their browser.
tuliplivechat.checkForAvailableAssociates('<PROJECT_DOMAIN>', '<AVAILABILITY_AUTH_TOKEN>').then((result) => {
// do some code
}).catch((error) => {
// do some code
});
Below is the list of localizable text strings that can be modified.
If an option is not given a custom string, the default value will be used.
Option | Default value |
---|---|
actionPostbackError | An error occurred while processing your action. Please try again. |
awayModeMessageAssigned | Hi {customerName}, I am currently unavailable to respond to your message. If you leave your phone number, I will get back to you as soon as possible. |
awayModeMessagePooled | Hi {customerName}! It appears that none of our associates are currently available. If you'd like to leave us a message and your phone number, an associate will get back to you as soon as possible. |
clickToRetry | Message not delivered. Click to retry. |
clickToRetryForm | Form not submitted. Click anywhere on the form to retry. |
connectNotificationSingleButtonText | Switch to |
connectNotificationText | Sync your conversation and continue messaging us through your favorite app. |
connectNotificationSingleText | Be notified when you get a reply. |
connectNotificationOthersText | others |
contactUsButtonText | Contact Us |
conversationTimestampHeaderFormat | MMMM D YYYY, h:mm A |
couldNotConnect | Couldn't connect. You can retry. |
couldNotConnectInner | retry connecting now |
couldNotConnectWithRetry | Couldn't connect. We'll keep retrying, or you can retry. |
couldNotConnectWithRetryInner | try now |
deleteConfirmation | Are you sure you want to delete this message? |
emailChangeAddress | Change my email |
emailDescription | To be notified by email when you get a reply, enter your email address. |
emailFieldLabel | Your email |
emailFieldPlaceholder | Your email address |
emailFormButton | Continue |
fetchHistory | Load more |
fetchingHistory | Retrieving history... |
fileTooLargeError | Max file size limit exceeded ({size}) |
fileTypeError | Unsupported file type. |
formErrorInvalidEmail | Email is invalid |
formErrorNoLongerThan | Must contain no more than ({characters}) characters |
formErrorNoShorterThan | Must contain at least ({characters}) characters |
formErrorUnknown | This doesn't look quite right |
formFieldSelectPlaceholderFallback | Choose one... |
frontendEmailChannelDescription | To talk to us using email just send a message to our email address and we'll reply shortly: |
headerMessage | Start chatting live with an associate, or reach out to customer support using the link below. |
headerText | How can we help? |
imageClickToReload | Click to reload image. |
imageClickToView | Click to view {size} image. |
imagePreviewNotAvailable | Preview not available. |
inputPlaceholder | Type a message... |
inputPlaceholderBlocked | Complete the form above... |
introAppText | Message us below or from your favourite app. |
introductionText | We're here to talk, so ask us anything! |
linkError | An error occurred when attempting to generate a link for this channel. Please try again. |
messageError | An error occurred while sending your message. Please try again. |
messageIndicatorTitlePlural | ({count}) New messages |
messageIndicatorTitleSingular | ({count}) New message |
messageRelativeTimeDay | {value}d ago |
messageRelativeTimeHour | {value}h ago |
messageRelativeTimeJustNow | Just now |
messageRelativeTimeMinute | {value}m ago |
messageTimestampFormat | h:mm A |
messageSending | Sending... |
messageDelivered | Delivered |
messengerChannelDescription | Connect your Facebook Messenger account to be notified when you get a reply and continue the conversation on Facebook Messenger. |
notificationSettingsChannelsDescription | You can also talk to us from your favourite app or service. |
notificationSettingsChannelsTitle | Other Channels |
notificationSettingsConnected | Connected |
notificationSettingsConnectedAs | Connected as {username} |
prechatCaptureGreetingText | Please fill out the form to get connected with an associate. |
prechatCaptureNameLabel | Name |
prechatCaptureNamePlaceholder | Enter your name |
prechatCaptureEmailLabel | |
prechatCaptureEmailPlaceholder | name@company.com |
prechatCaptureConfirmationText | Thanks! We are attempting to find an associate for you. |
prechatCaptureMailgunLinkingConfirmation | You'll be notified here and by email at {email} once we reply. |
sendButtonText | Send |
settingsHeaderText | Settings |
shareLocation | Share location |
smsBadRequestError | We were unable to communicate with this number. Try again or use a different one. |
smsCancel | Cancel |
smsChangeNumber | Change my number |
smsChannelDescription | Connect your SMS number to be notified when you get a reply and continue the |
smsChannelPendingDescription | Check your messages at {number} to confirm your phone number. |
smsContinue | Continue |
smsInvalidNumberError | Your phone number isn't valid. Please try again. |
smsLinkCancelled | Link to {appUserNumber} was cancelled. |
smsLinkPending | Pending |
smsPingChannelError | There was an error sending a message to your number. |
smsSendText | Send me a text |
smsStartTexting | Start Texting |
smsTooManyRequestsError | A connection for that number was requested recently. Please try again in |
smsTooManyRequestsOneMinuteError | A connection for that number was requested recently. Please try again in 1 minute. |
smsUnhandledError | Something went wrong. Please try again. |
tapToRetry | Message not delivered. Tap to retry. |
tapToRetryForm | Form not submitted. Tap anywhere on the form to retry. |
unsupportedMessageType | Unsupported message type. |
unsupportedActionType | Unsupported action type. |
uploadInvalidError | Invalid file. |
uploadPhoto | Upload photo. |
uploadVirusError | A virus was detected in your file and it has been rejected |
Customizable strings in customText
can be localized. They are contained in an object that has the locale as its key.
var textValues = {
'en-US': {
headerText: 'Hello!'
},
'fr-FR': {
headerText: 'Bonjour!'
}
};
The browsers language (navigator.language
) is used to determine which translation to provide. en-US
is the fallback default.
Language | Code |
---|---|
English (USA) - Default | en-US |
German | de |
French | fr |
French (Canadian) | fr-CA |
Spanish | es |
Italian | it |
Japanese | ja |
Korean | ko |
Portuguese | pt |
Chinese (Simplified) | zh-CN |
Chinese (Hong Kong) | zh-HK |
Chinese (Taiwan) | zh-TW |
By default, all the languages above are supported by the web chat widget. If you only want to support a specific set of languages, simply include the supportedLanguages field with an array of the language codes you want to continue to support. If the customer's browser is not in a language that is supported, the widget will default to the fallbackLanguageCode.
NOTE: The fallback language code must be included in the supported languages array
tuliplivechat.init({
integrationId: '<INTEGRATION_ID>',
fallbackLanguageCode: 'fr',
supportedLanguages: ['fr', 'it', 'de']
});
var textValues = {
'en-US': {
prechatCaptureGreetingText: 'Please fill out the form to get connected with a fashion advisor.',
prechatCaptureConfirmationText: 'Thanks for that, so good. We are attempting to find a fashion advisor for you.',
headerText: 'Haute Couture Inc.'
}
};
tuliplivechat.init({
integrationId: '<INTEGRATION_ID>',
customText: textValues
});
In the latest version, we've added support for tracking the page a conversation was initialized. This captures the URL and title of the current page the user is on when they send their first message to LiveConnect, and displays it within the application.
In order to track the user's browsing when the widget is hosted in the EU, we require their consent via cookies. To enable this feature on your e-commerce site, we require a cookie with the key tulipLiveChatAllowPageTracking to be set to true. This can be added into your site's standard cookie policy.
In order to populate the image icon on the LiveConnect application, you need to provide the pageReferenceImageSelector configuration init your widget's configurations. This value should be a DOM selector string that represents the single image object that you want to have selected. The src
property of the found object will be used on the LiveConnect application in the E-Commerce Page tracking element. If multiple elements are found on the DOM from the selector or no elements are found, no image will be used.
<div>
<img src="http://images.liveconnect/123.png" id="tulip-e-commerce-tracking-image">
</div>
tuliplivechat.init({
...,
pageReferenceImageSelector: '#tulip-e-commerce-tracking-image'
})
Note: You do not have to include the 'img' tag in your selector.
In order to have your customers have the ability to delete messages they have sent, you must add the following configuration to your widget's initialization configurations. Once set, all messages sent from the customer will be able to be deleted.
tlc.init({
integrationId: '<INTEGRATION_ID>',
userCanDeleteSentMessages: true
});
In order to delete a message, a customer will right-click (longpress on mobile devices) on a message. A trash can icon will appear to the left of the message. Once pressed, there will be a confirmation dialog asking the use to confirm the deletion of this message. If the customer confirms, the message will be deleted on both the widget and the LiveConnect application.
Confirmation text can be customized using the deleteConfirmation
key.
If you would like to trigger your own events on events within the widget, you can do that by defining your own methods to run during a tuliplivechat.on
call. The method takes two parameters, the trigger and callback.
This event triggers when a new conversation is started within the widget. Data passed in is a conversationObject.
tuliplivechat.on('conversation:start', (conversationObject) => {
console.log('A new conversation was started', conversationObject);
});
This event triggers when a conversation ended by the customer or the associate. Data passed in is a conversationObject.
tuliplivechat.on('conversation:end', (conversationObject) => {
console.log('A conversation was end', conversationObject);
});
This event triggers when a user sends a message from the widget to the associate. Data passed in is a messageObject.
tuliplivechat.on('message:sent', (messageObject) => {
console.log('A message was sent', messageObject);
});
This event triggers when a user receives a message from the associate. Data passed in is a messageObject.
tuliplivechat.on('message:received', (messageObject) => {
console.log('A message was received', messageObject);
});
This event triggers when the widget is opened.
tuliplivechat.on('widget:opened', () => {
console.log('The widget was opened');
});
This event triggers when the widget is closed.
tuliplivechat.on('widget:closed', () => {
console.log('The widget was closed');
});
These are samples of the objects returned to the Widget Events
{
conversationId: "cb4605c1be77e3dd7187f252"
timestamp: 1632798135213
}
// Type = text
{
conversationId: "cb4605c1be77e3dd7187f252"
id: "61524c86a5663b00daaa24b0"
text: "Hello"
timestamp: 1632797894134
type: "text"
}
// Type = image
{
altText: "image.jpg"
conversationId: "cb4605c1be77e3dd7187f252"
id: "61524cfa1d129100d9fb499c"
mediaSize: 14687
mediaType: "image/jpeg"
mediaUrl: "https://media.smooch.io/apps/5f58f0194d4f27000e26fe2f/conversations/cb4605c1be77e3dd7187f252/4qLuTy1La2VkKTXpKMSTIg0D/download.jpg"
text: undefined
timestamp: 1632798012693
type: "image"
}
// Type = video
{
altText: "TestVideo.mov"
conversationId: "cb4605c1be77e3dd7187f252"
id: "61524d39a84d1100daf360df"
mediaSize: 993303
mediaType: "video/quicktime"
mediaUrl: "https://media.smooch.io/apps/5f58f0194d4f27000e26fe2f/conversations/cb4605c1be77e3dd7187f252/0HKUYvKvVvX9KoZRvwU7N7Rg/TestVideo.mov"
text: undefined
timestamp: 1632798073454
type: "video"
}
If you would like to open or close the widget via the keyboard, these actions can now be done through the use of using the tab
and enter
keys.
To open the widget, you must press tab
until the widget is highlighted. Once highlighted, the user must press enter
which will open the chat window up.
The user can get to the input field in the chat window without needing a mouse by tabbing over to it until the field is active. Once active, the user can type.
To close the widget, you must press tab
until the "X" button is highlighted in the chat window. Once that occurs, the user will need to press the enter
key to close the widget.