Custom Components
reachat is completely customizable. You can change the look and feel of the chat by customizing the theme or by providing your own components. Components can even be overriden using slots (opens in a new tab).
Custom Components Example
Below is example markup that creates a custom session empty message and also provides a custom session list item.
const CustomMessageQuestion: FC<any> = ({ question, files }) => (
<>
<span className="text-lg font-semibold text-blue-500">
This is my question: {question}
</span>
<MessageFiles files={files}>
<CustomMessageFile />
</MessageFiles>
</>
);
const CustomMessageResponse: FC<any> = ({ response }) => (
<blockquote className="border-l border-blue-500 pl-2">
This is the response: {response}
</blockquote>
);
const CustomMessageFile: FC<any> = ({ name, type }) => (
<Chip size="small" className="rounded-full border border-gray-700">
{name || type}
</Chip>
);
const CustomMessageSource: FC<any> = ({ title, url, image }) => {
const { theme } = useContext(ChatContext);
return (
<Chip
size="small"
className="rounded-full border border-blue-500 border-opacity-50"
onClick={() => alert('take me to ' + url)}
start={
image && (
<img
src={image}
alt={title}
className={cn(theme.messages.message.sources.source.image)}
/>
)
}
>
{title || url}
</Chip>
);
};
const CustomSessionListItem: FC<SessionListItemProps> = ({
session,
children,
...rest
}) => {
const [open, setOpen] = useState(false);
const btnRef = useRef(null);
return (
<>
<ListItem
{...rest}
end={
<IconButton
ref={btnRef}
size="small"
variant="text"
onClick={e => {
e.stopPropagation();
setOpen(true);
}}
>
<MenuIcon />
</IconButton>
}
>
<span className="truncate">{session.title}</span>
</ListItem>
<Menu
open={open}
onClose={() => setOpen(false)}
reference={btnRef}
appendToBody={false}
>
<Card disablePadding>
<List>
<ListItem onClick={() => alert('rename')}>Rename</ListItem>
<ListItem onClick={() => alert('delete')}>Delete</ListItem>
</List>
</Card>
</Menu>
</>
);
};
Then in the master component you can leverage them like:
export const CustomComponents = () => {
return (
<div
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
padding: 20,
margin: 20,
background: '#02020F',
borderRadius: 5
}}
>
<Chat
sessions={[
...fakeSessions,
...sessionsWithFiles,
...sessionWithSources
]}
activeSessionId="1"
>
<SessionsList>
<NewSessionButton>
<button className="text-blue-500">New Session</button>
</NewSessionButton>
<Divider variant="secondary" />
<SessionGroups>
{groups =>
groups.map(({ heading, sessions }) => (
<SessionsGroup heading={heading} key={heading}>
{sessions.map(s => (
<SessionListItem key={s.id} session={s}>
<CustomSessionListItem session={s} />
</SessionListItem>
))}
</SessionsGroup>
))
}
</SessionGroups>
</SessionsList>
<SessionMessagePanel>
<SessionMessagesHeader>
<CustomMessagesHeader />
</SessionMessagesHeader>
<SessionMessages>
{conversations =>
conversations.map((conversation, index) => (
<SessionMessage
conversation={conversation}
isLast={index === conversations.length - 1}
key={conversation.id}
>
<MessageQuestion
question={conversation.question}
files={conversation.files}
>
<CustomMessageQuestion />
</MessageQuestion>
<MessageResponse response={conversation.response}>
<CustomMessageResponse />
</MessageResponse>
<MessageSources sources={conversation.sources}>
<CustomMessageSource />
</MessageSources>
<MessageActions
question={conversation.question}
response={conversation.response}
/>
</SessionMessage>
))
}
</SessionMessages>
<ChatInput />
</SessionMessagePanel>
</Chat>
</div>
);
};
Using SessionContext
The SessionContext
hook provides access to the current session state and methods to
interact with it. Here's how you can use it:
import { useSessionContext } from 'reachat';
const CustomSendButton = () => {
const { sendMessage } = useSessionContext();
const handleSend = () => {
sendMessage('Hello, AI!');
return <button onClick={handleSend}>Send Custom Message</button>;
};
};
The SessionContext
hook provides the following properties and methods:
export interface SessionContextProps {
sessions: Session[];
activeSessionId: string | null;
theme?: ChatTheme;
isLoading?: boolean;
activeSession?: Session | null;
remarkPlugins?: PluggableList[];
selectSession?: (sessionId: string) => void;
deleteSession?: (sessionId: string) => void;
createSession?: () => void;
}
By using these overrides and the SessionContext
hook, you can create a fully customized chat
experience while still leveraging the core functionality of reachat.