Building a working chat bot in Framer X.

Framer X is an interaction design tool for building React powered interfaces. Learn how to build a chat bot in this tutorial.

Ryan Barry
10 min readOct 12, 2018
ChatterBot, a free chat bot kit. Download it in the Framer X Store today!

Start fresh

First, open a new fresh Framer X project file and open the Components tab. From here we will need three separate code components, a chat bubble, a message input and a chat window.

The Chat Bubble

  1. Create a new Code component and name it ChatBubble.
  2. You can leave the two import statements, but delete the rest of the code inside the generated code file.
  3. Follow the imports with our class constructor.
  4. Use two divs with our message nested inside to control our bubble sizing.
import * as React from "react";
import { PropertyControls, ControlType } from "framer";
export class ChatBubble extends React.Component<Props> {
render() {
return (
<div>
<div>Chat Message</div>
</div>
);
}
}

Let’s add two CSS styles after our render() function. Then assign them to their respective divs.

import * as React from "react";
import { PropertyControls, ControlType } from "framer";
export class ChatBubble extends React.Component<Props> {
render() {
const containerStyle: React.CSSProperties = {}
const bubbleStyle: React.CSSProperties = {}
return (
<div style={containerStyle}>
<div style={bubbleStyle}>Chat Message</div>
</div>
);
}
}

Now fill the styles to give our ChatBubble component some shape. We needed two divs in order to let the inner bubble take its size based on the text inside of it. To do this we will tell the container to base its size on the component while the bubble will have a width and height of "auto". Let’s also give the bubble a temporary background color and make sure to set its display to inline-block so the container knows to hug its text.

To grab the components width, use this.props.width , same goes for the height. Also give the container some flex styling, we’ll need to set the flex direction to control which side the bubble should display on.

...const containerStyle: React.CSSProperties = {
width: this.props.width,
height: this.props.height,
// Flex Styles
display: "flex",
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "flex-start",
}
const bubbleStyle: React.CSSProperties = {
width: "auto",
height: "auto",
background: "pink",
display: "inline-block",
}
...

To complete this ChatBubble component we will add some property controls that expose the background color, text color and message inside the bubble. We will also use a toggle to flip the bubble from the left to the right. First let’s state our interface Prop under the import statements, then we add the Framer X property control options before our render() function.

import * as React from "react";
import { PropertyControls, ControlType } from "framer";
interface Props {
width: number;
height: number;
message: string;
background: string;
color: string;
side: "left" | "right";
}
export class ChatBubble extends React.Component<Props> { static defaultProps = {
message: "How are you?",
background: "#F1EFF6",
color: "#333333",
side: "left",
}
static propertyControls: PropertyControls = {
message: { type: ControlType.String, title: "Message" },
background: { type: ControlType.Color, title: "Background" },
color: { type: ControlType.Color, title: "Text" },
side: {
type: ControlType.SegmentedEnum,
options: ["left", "right"],
title: "Side"
}
}
render()...

Now we can attach the property names to our styles in order to control them, add some extra styling if you desire. We also need to replace the string inside our bubble div to {this.props.message} so its hooked in sync with our message prop.

...render() {  const containerStyle: React.CSSProperties = {
width: this.props.width,
height: this.props.height,
// Flex Styles
display: "flex",
flexDirection: this.props.side === "left" ? "row" : "row-reverse",
justifyContent: "flex-start",
alignItems: "flex-start",
}
const bubbleStyle: React.CSSProperties = {
width: "auto",
height: "auto",
background: this.props.background,
color: this.props.color,
padding: "6px 9px",
marginBottom: "6px",
borderRadius: "6px",
display: "inline-block",
font: "500 14px/18px SF Pro Text",
letterSpacing: "-0.2px",
}
return (
<div style={containerStyle}>
<div style={bubbleStyle}>{this.props.message}</div>
</div>
);
}
...

And that will complete our ChatBubble component. As you can see we simply control the bubble direction with this simple conditional statement

flexDirection: this.props.side === "left" ? "row" : "row-reverse"
Our ChatBubble component, complete with message, side and color controls.

Message Input

We know for our bot that the user should be able to enter a message and hit “Enter” to send it to the chat window. Then, the bot will reply with a new message in the chat window.

Lets create an input that listens for the “Enter” key being pressed and pass that event along to its parent—which in this project is the chat window.

To save time let’s take some search bar code already provided for us in the Framer X Store.

  1. First open the Store tab.
  2. Search for the Example Kit provided by the Framer team.
  3. Install the package and head back to your Components tab.
  4. You should now see a list of components under the Example Kit title bar. Look for the SearchBar component and right-click, and copy the code.

Instead of just using the provided search bar we will create our own based on the code provided by the Example Kit. We need to do this in order to add a new keyboard listener and pass the event through its props.

  1. With our copied code in our clipboard, add a new code component to our file. Name it MessageInput, delete everything inside and paste in our copied code. Make sure you do a find/replace and change all the SearchBar labels to MessageInput and hit save.
  2. If you wish you can uninstall the Example Kit as we no longer need it.
  3. Now we can create our keyboard event inside our MessageInput component. Inside our interface Props {} add a new event prop.
// Pass the value as a string
onEnterKey: (value: string) => void

Now the fun part, lets add our onEnterKey() event. It consists of two parts, the event itself and then attaching the event to the HTML <input/> tag.

onEnterKey = (event) => {
const value = event.nativeEvent.target.value
// Enter Key Pressed
if (event.nativeEvent.keyCode === 13) {
this.props.onEnterKey ? this.props.onEnterKey(value) : null
}
}
render() ...

Now to attach the event to our tag we will use onKeyPress to handle the event every-time the user pounds a key into our input. That includes backspaces and selection-deletes. For a full list of React events reference this link.

<input
onChange={this.onChange}
onKeyPress={this.onEnterKey}
value={value}
placeholder={placeholder}
style={{ ...style, backgroundColor, color: textColor }}
/>

Let’s clean up the component by adding the CSS styles inside our constructor, remove the borderRadius and absolute properties, add outline: “none” and set our width and height based on the components size.

...render() {
const { placeholder, backgroundColor, textColor } = this.props
const { value } = this.state
const style: React.CSSProperties = {
width: this.props.width,
height: this.props.height,
border: "none",
outline: "none",
paddingLeft: 8,
paddingRight: 8,
}
...

That’s all we need to do for the MessageInput. Now save our component and we can move onto the chat window.

Pull it all together with the Chat Window

Create one last code component and name it ChatWindow. Empty the file and create the base code with two import statements, the interface props, the class constructor and two css styles placed inside the constructor.

import * as React from "react";
import { PropertyControls, ControlType } from "framer";
interface Props {
width: number;
height: number;
}
export class ChatWindow extends React.Component<Props> {
render() {
const containerStyle: React.CSSProperties = {}
const listStyle: React.CSSProperties = {}
return (
<div style={containerStyle}></div>
);
}
}

Now we will import our ChatBubble and MessageInput components into our ChatWindow. After doing so build out the html template using our imported components. Feel free to style your container and list however you like.

import * as React from "react";
import { PropertyControls, ControlType } from "framer";
import { ChatBubble } from "./ChatBubble";
import { MessageInput } from "./MessageInput";
interface Props {
width: number;
height: number;
}
export class ChatWindow extends React.Component<Props> { render() { const containerStyle: React.CSSProperties = {
width: this.props.width,
height: this.props.height,
background: '#FFFFFF',
borderRadius: "6px",
overflow: "hidden",
// Flex Styling
display: "flex",
flexDirection: "column",
}
const listStyle: React.CSSProperties = {
height: "100%",
margin: 0,
padding: 8,
overflowY: "scroll",
listStyle: "none",
borderBottom: "1px #EEEEEE solid",
}
return (
<div style={containerStyle}>
<ul style={listStyle}>
<ChatBubble width={"100%"} height={"auto"}/>
</ul>
<MessageInput
width={"100%"}
backgroundColor={"transparent"}
placeholder={"Ask a question..."}
/>
</div>
);
}
}

Let’s hit save and view our component in the Framer X canvas. After dragging the component on-screen you should see the same ChatBubble component inside our list, and our MessageInput component inside our container.

Our ChatWindow containing both the MessageInput and ChatBubble components.

Since we gave our <ChatBubble /> a width of 100% and a height of auto , our ChatBubble component can be duplicated inside the list and we will start to see a conversation feed arise.

Next we create a new method that will will hook into our MessageInput and fire every time our onEnterKey event is triggered. From there we will need to create a new state of data to hold messages in an array, those messages will then be mapped into our <ul> and determine the properties for each ChatBubble.

Let’s get code fancy

First, we setup our method then bind it to our component. From there we can create our state to hold the message array.

  1. Create a new method called triggerMessage() and pass along the value string.
  2. Right inside our class we’re going to open up the constructor() method and pass along the props.
  3. Create a binding to our triggerMessage.
  4. Build an empty array of data within our state.
  5. Fill out our triggerMessage method by using the React function, setState({}).
  6. Create an object of data that holds the message and which side to show the message.
  7. Add our value to our list of data.
export class ChatWindow extends React.Component<Props> {
constructor(props){
super(props);
this.triggerMessage = this.triggerMessage.bind(this);
this.state = {
data: []
}
}
triggerMessage(value) {
this.setState({
data: [...this.state.data,
{
"side" : "left",
"message" : value
},
]
});
}
render() ...

Next we attach the triggerMessage method to our MessageInput component inside our component template. We can do that easily by using the onEnterKey prop we passed in our MessageInput.

...<MessageInput 
width={"100%"}
backgroundColor={"transparent"}
placeholder={"Ask a question..."}
onEnterKey={this.triggerMessage}
/>
...

Now to create our message listing we will use a map function to sift through our data and add the messages based on our users input. Inside the map function we need to pass the index to calculate the list keys and then we can attach our value by using message={item.message} and we attach our side conditional the same way.

This mapping will replace our HTML <ChatBubble /> tag, and instead the ChatBubble will be placed inside the function.

...<ul style={listStyle}>
{this.state.data.map((item, index) => (
<ChatBubble
key={index}
width={'100%'}
height={'auto'}
message={item.message}
side={item.side}
/>
))}
</ul>
...

If we save our component and head over to our Framer canvas, you’ll notice the first message has disappeared. This is because now our message list is being controlled by out state.data.

We can preview the ChatWindow and test it out, if done correctly, you’ll see a new message appear in your list every time you type a message into the input and press the enter key.

Customize your chat bot

The next steps are based on however you want your chat bot to respond to the user input. For instance, maybe you want to listen for a key-word like “weather” and then display a message containing today’s weather. Or maybe we want our bot to respond to every message we send and it’s response would be randomly pulled from an data set of chatbot messages.

To keep it simple i’ll explain the steps on how to add a response method and then link to an example file in the store that you can explore for more ideas on how to control the bot responses.

  1. Make sure you’re inside the ChatWindow component file.
  2. Create a new method under our triggerMessage called sendReply.
  3. Inside the method add a setTimeout() function which will delay the response by a set time. We’ll use 1500 milliseconds in this example.
  4. Then just as before, include the same setState({}) function as we did for the triggerMessage. But instead of passing the value as the message, we can include a custom string to push through. We also need to set the data side to “right”.
  5. At the end of our triggerMessage method we will call our new sendReply() method.
triggerMessage(value) {
this.setState({
data: [...this.state.data,
{
"side" : "left",
"message" : value
},
]
});
this.sendReply()
}
sendReply() {
setTimeout(() => {
this.setState({
data: [...this.state.data,
{
"side" : "right",
"message" : "Offline till 9:00 AM"
},
]
});
}, 1500);
}

Now if we head back to the preview, you’ll notice after you type and hit send, a slight delay happens then the bot replies with our new string, Offline till 9:00 AM and it will appear on the right side.

Working with code components in Framer X can be tricky if you’re a designer like me. But the best learning tool I’ve come across has been using the in-app store to download and learn from others. If you ran into trouble with this tutorial, you can download the final .framerx file below.

Download the final file.

If you want to check out a more advanced version of this chat bot you can download my free package in the Framer X Store. Search for “Chat Bot” in the store or click the link below.

Chat Bot Component — Framer X Store link.

ChatterBot, a free chat bot kit. Download it in the Framer X Store today!

Additional Framer X Resources

--

--