suggestedActions component in vercel/ai-chatbot source code.

In this article, we will review what happens when you click on “What is the weather” widget on chat.vercel.ai. Let’s find out. Let’s start from this UI element “What is the weather”. I searched across the codebase for this string and I found this in components/suggested-actions. function PureSuggestedActions({ chatId, append }: SuggestedActionsProps) { const suggestedActions = [ { title: 'What are the advantages', label: 'of using Next.js?', action: 'What are the advantages of using Next.js?', }, { title: 'Write code to', label: `demonstrate djikstra's algorithm`, action: `Write code to demonstrate djikstra's algorithm`, }, { title: 'Help me write an essay', label: `about silicon valley`, action: `Help me write an essay about silicon valley`, }, { title: 'What is the weather', label: 'in San Francisco?', action: 'What is the weather in San Francisco?', }, ]; return ( {suggestedActions.map((suggestedAction, index) => ( 1 ? 'hidden sm:block' : 'block'} > { window.history.replaceState({}, '', `/chat/${chatId}`); append({ role: 'user', content: suggestedAction.action, }); }} className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start" > {suggestedAction.title} {suggestedAction.label} ))} ); } So what is happening on clicking a button here? onClick={async () => { window.history.replaceState({}, '', `/chat/${chatId}`); append({ role: 'user', content: suggestedAction.action, }); }} Two side-effects: window.history.replaceState append append here is a prop passed to PureSuggestedActions. interface SuggestedActionsProps { chatId: string; append: UseChatHelpers['append']; } function PureSuggestedActions({ chatId, append }: SuggestedActionsProps) { and this function memoized and assigned to SuggestedActions as shown below at the end of the file export const SuggestedActions = memo(PureSuggestedActions, () => true); Okay, so where is this SuggestedActions component is used then? well, it is found to be used in components/multimodal-input.tsx return ( {messages.length === 0 && attachments.length === 0 && uploadQueue.length === 0 && ( )} That makes sense, if you think about it, these suggestions only popup when there is no messages in the chat.  The same pattern is found in the multimodal-inpiut, there is a memoized assignment as shown below. export const MultimodalInput = memo( PureMultimodalInput, (prevProps, nextProps) => { if (prevProps.input !== nextProps.input) return false; if (prevProps.status !== nextProps.status) return false; if (!equal(prevProps.attachments, nextProps.attachments)) return false; return true; }, ); and this is, in turn, used in components/chat.tsx const { messages, setMessages, handleSubmit, input, setInput, append, status, stop, reload, } = useChat({ id, body: { id, selectedChatModel: selectedChatModel }, initialMessages, experimental_throttle: 100, sendExtraMessageFields: true, generateId: generateUUID, onFinish: () => { mutate(unstable_serialize(getChatHistoryPaginationKey)); }, onError: () => { toast.error('An error occurred, please try again!'); }, }); useChat is imported as shown below: import { useChat } from '@ai-sdk/react'; Really, calling “append” on clicking that suggested action shows that how easy it is to integrate and build chat systems using Vercel APIs. About me: Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos. I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com My Github —  https://github.com/ramu-narasinga My website —  https://ramunarasinga.com My Youtube channel —  https://www.youtube.com/@ramu-narasinga Learning platform —  https://thinkthroo.com Codebase Architecture —  https://app.thinkthroo.com/architecture Best practices —  https://app.thinkthroo.com/best-practices Production-grade projects —  https://app.thinkthroo.com/production-grade-projects References: https://github.com/vercel/ai-chatbot/blob/main/lib/ai/tools/get-weather.ts https://chat.vercel.ai/ https://github.com/vercel/ai-chatbot/blob/main/app/(chat)/api/chat/route.ts#L93 https://github.com/vercel/ai-chatbot/blob/main/components/multimodal-input.tsx#L271 https://github.com/vercel/ai-chatbot/blob/dfda9118d9291a9e21f91bf4eba7e80dcfd4bc49/components/s

Apr 16, 2025 - 05:29
 0
suggestedActions component in vercel/ai-chatbot source code.

In this article, we will review what happens when you click on “What is the weather” widget on chat.vercel.ai. Let’s find out.

Image description

Let’s start from this UI element “What is the weather”. I searched across the codebase for this string and I found this in components/suggested-actions.

function PureSuggestedActions({ chatId, append }: SuggestedActionsProps) {
  const suggestedActions = [
    {
      title: 'What are the advantages',
      label: 'of using Next.js?',
      action: 'What are the advantages of using Next.js?',
    },
    {
      title: 'Write code to',
      label: `demonstrate djikstra's algorithm`,
      action: `Write code to demonstrate djikstra's algorithm`,
    },
    {
      title: 'Help me write an essay',
      label: `about silicon valley`,
      action: `Help me write an essay about silicon valley`,
    },
    {
      title: 'What is the weather',
      label: 'in San Francisco?',
      action: 'What is the weather in San Francisco?',
    },
  ];

  return (
    <div
      data-testid="suggested-actions"
      className="grid sm:grid-cols-2 gap-2 w-full"
    >
      {suggestedActions.map((suggestedAction, index) => (
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 20 }}
          transition={{ delay: 0.05 * index }}
          key={`suggested-action-${suggestedAction.title}-${index}`}
          className={index > 1 ? 'hidden sm:block' : 'block'}
        >
          <Button
            variant="ghost"
            onClick={async () => {
              window.history.replaceState({}, '', `/chat/${chatId}`);

              append({
                role: 'user',
                content: suggestedAction.action,
              });
            }}
            className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start"
          >
            <span className="font-medium">{suggestedAction.title}</span>
            <span className="text-muted-foreground">
              {suggestedAction.label}
            </span>
          </Button>
        </motion.div>
      ))}
    </div>
  );
}

So what is happening on clicking a button here?

onClick={async () => {
  window.history.replaceState({}, '', `/chat/${chatId}`);

  append({
    role: 'user',
    content: suggestedAction.action,
  });
}}

Two side-effects:

  1. window.history.replaceState

  2. append

append here is a prop passed to PureSuggestedActions.

interface SuggestedActionsProps {
  chatId: string;
  append: UseChatHelpers['append'];
}

function PureSuggestedActions({ chatId, append }: SuggestedActionsProps) {

and this function memoized and assigned to SuggestedActions as shown below at the end of the file

export const SuggestedActions = memo(PureSuggestedActions, () => true);

Okay, so where is this SuggestedActions component is used then? well, it is found to be used in components/multimodal-input.tsx

 return (
    <div className="relative w-full flex flex-col gap-4">
      {messages.length === 0 &&
        attachments.length === 0 &&
        uploadQueue.length === 0 && (
          <SuggestedActions append={append} chatId={chatId} />
        )}

      <input
        type="file"
        className="fixed -top-4 -left-4 size-0.5 opacity-0 pointer-events-none"
        ref={fileInputRef}
        multiple
        onChange={handleFileChange}
        tabIndex={-1}
      />

That makes sense, if you think about it, these suggestions only popup when there is no messages in the chat. 

The same pattern is found in the multimodal-inpiut, there is a memoized assignment as shown below.

export const MultimodalInput = memo(
  PureMultimodalInput,
  (prevProps, nextProps) => {
    if (prevProps.input !== nextProps.input) return false;
    if (prevProps.status !== nextProps.status) return false;
    if (!equal(prevProps.attachments, nextProps.attachments)) return false;

    return true;
  },
);

and this is, in turn, used in components/chat.tsx

 const {
    messages,
    setMessages,
    handleSubmit,
    input,
    setInput,
    append,
    status,
    stop,
    reload,
  } = useChat({
    id,
    body: { id, selectedChatModel: selectedChatModel },
    initialMessages,
    experimental_throttle: 100,
    sendExtraMessageFields: true,
    generateId: generateUUID,
    onFinish: () => {
      mutate(unstable_serialize(getChatHistoryPaginationKey));
    },
    onError: () => {
      toast.error('An error occurred, please try again!');
    },
  });

useChat is imported as shown below:

import { useChat } from '@ai-sdk/react';

Really, calling “append” on clicking that suggested action shows that how easy it is to integrate and build chat systems using Vercel APIs.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com

My Github —  https://github.com/ramu-narasinga

My website —  https://ramunarasinga.com

My Youtube channel —  https://www.youtube.com/@ramu-narasinga

Learning platform —  https://thinkthroo.com

Codebase Architecture —  https://app.thinkthroo.com/architecture

Best practices —  https://app.thinkthroo.com/best-practices

Production-grade projects —  https://app.thinkthroo.com/production-grade-projects

References:

  1. https://github.com/vercel/ai-chatbot/blob/main/lib/ai/tools/get-weather.ts

  2. https://chat.vercel.ai/

  3. https://github.com/vercel/ai-chatbot/blob/main/app/(chat)/api/chat/route.ts#L93

  4. https://github.com/vercel/ai-chatbot/blob/main/components/multimodal-input.tsx#L271

  5. https://github.com/vercel/ai-chatbot/blob/dfda9118d9291a9e21f91bf4eba7e80dcfd4bc49/components/suggested-actions.tsx#L74

  6. https://github.com/vercel/ai-chatbot/blob/main/components/chat.tsx#L90