# Suggestion

Short prompts that people can send to an agent in one click, in a row above the prompt input.

Source: https://suiss.app/ui/docs/ai/suggestion

**React**

**Example**

```tsx
"use client"

import { ArrowUpIcon, PlusIcon } from "@phosphor-icons/react"
import * as React from "react"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Button } from "@/components/ui/button"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupTextarea,
} from "@/components/ui/input-group"
import { Message, MessageContent } from "@/components/ui/message"

const suggestions = [
  "Add a dark mode toggle",
  "Fix the failing build",
  "Write tests for the form",
  "Upgrade to Next.js 16",
  "Add a loading state",
  "Find unused dependencies",
]

const replies: Record<string, string> = {
  "Add a dark mode toggle":
    "Added a ModeToggle to the site header. It calls setTheme from next-themes.",
  "Fix the failing build":
    "The build failed on a missing import in app/page.tsx. I added it and the build passes.",
  "Write tests for the form":
    "Added four tests in signup-form.test.tsx. They cover the empty, invalid and valid states.",
  "Upgrade to Next.js 16":
    "Ran the codemod and bumped next to 16. Two routes needed async params, so I updated them.",
  "Add a loading state":
    "Added a loading.tsx to the dashboard route. It shows skeletons while the data loads.",
  "Find unused dependencies":
    "Three packages are not imported anywhere: lodash, moment and classnames. Should I remove them?",
}

export default function SuggestionDemo() {
  const [text, setText] = React.useState("")
  const [turn, setTurn] = React.useState<{
    prompt: string
    reply: string
  } | null>(null)
  const formRef = React.useRef<HTMLFormElement>(null)
  const canSend = text.trim().length > 0

  function send(prompt: string) {
    setTurn({
      prompt,
      reply:
        replies[prompt] ?? "This demo only knows the suggestions. Pick one.",
    })
    setText("")
  }

  function onSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault()
    if (!canSend) {
      return
    }

    send(text.trim())
  }

  return (
    <div className="flex w-full max-w-lg flex-col gap-6 py-6 text-sm">
      {turn && (
        <div className="flex flex-col gap-4">
          <Message align="end">
            <MessageContent>
              <Bubble align="end" variant="muted">
                <BubbleContent>{turn.prompt}</BubbleContent>
              </Bubble>
            </MessageContent>
          </Message>
          <Message>
            <MessageContent className="text-sm">
              <p>{turn.reply}</p>
            </MessageContent>
          </Message>
        </div>
      )}
      <div className="flex flex-col gap-2">
        <div className="flex gap-2 overflow-x-auto overscroll-x-contain [scrollbar-width:none]">
          {suggestions.map((suggestion) => (
            <Button
              key={suggestion}
              variant="outline"
              size="sm"
              className="shrink-0"
              onClick={() => send(suggestion)}
            >
              {suggestion}
            </Button>
          ))}
        </div>
        <form ref={formRef} onSubmit={onSubmit}>
          <InputGroup>
            <InputGroupTextarea
              value={text}
              onChange={(event) => setText(event.target.value)}
              placeholder="Ask the agent to change your code..."
              aria-label="Message"
              onKeyDown={(event) => {
                if (event.key === "Enter" && !event.shiftKey) {
                  event.preventDefault()
                  formRef.current?.requestSubmit()
                }
              }}
              className="p-3"
            />
            <InputGroupAddon align="block-end">
              <InputGroupButton
                size="icon-sm"
                variant="outline"
                className="rounded-full"
                aria-label="Attach files"
              >
                <PlusIcon />
              </InputGroupButton>
              <InputGroupButton
                type="submit"
                size="icon-sm"
                variant="default"
                className="ms-auto rounded-full"
                disabled={!canSend}
                aria-label="Send"
              >
                <ArrowUpIcon />
              </InputGroupButton>
            </InputGroupAddon>
          </InputGroup>
        </form>
      </div>
    </div>
  )
}
```

A suggestion is a prompt you send without typing. Each one is a [Button](https://suiss.app/ui/docs/components/button) with the prompt as its label. Put a row of them above the [Prompt Input](https://suiss.app/ui/docs/ai/prompt-input).

## Installation

Suggestions are built with Button and Input Group.

```bash title="Terminal"
npx shadcn@latest add @esuiss/button @esuiss/input-group
```

Or use the [suiss/ui CLI](https://suiss.app/ui/docs/cli):

```bash title="Terminal"
npx @esuiss/ui@latest add button input-group
```

## Usage

```tsx
import { Button } from "@/components/ui/button"
```

```tsx
<div className="flex gap-2 overflow-x-auto overscroll-x-contain">
  {suggestions.map((suggestion) => (
    <Button
      key={suggestion}
      variant="outline"
      size="sm"
      className="shrink-0"
      onClick={() => send(suggestion)}
    >
      {suggestion}
    </Button>
  ))}
</div>
```

The row scrolls sideways when the suggestions do not fit, and `shrink-0` keeps each label on one line.

## AI SDK

The label is the message. Send it as is.

```tsx
sendMessage({ text: suggestion })
```

## API Reference

See [Button](https://suiss.app/ui/docs/components/button#api-reference).

## Accessibility

- Each suggestion is a button whose label is the prompt, so it is announced as written.
- Keep labels short and specific, so the row can be scanned quickly.

**React Native, SwiftUI, Jetpack Compose**

```tsx
import { ScrollView, View } from "react-native"
import { Button } from "@/components/ui/button"
import { Text } from "@/components/ui/text"

const suggestions = [
  "Why does the build fail?",
  "Add dark mode",
  "Write tests for the cart",
  "Explain this error",
]

export function AiSuggestionExample() {
  return (
    <View className="w-full gap-3">
      <Text className="text-muted-foreground">Try asking</Text>
      <ScrollView
        horizontal
        showsHorizontalScrollIndicator={false}
        contentContainerClassName="gap-2"
      >
        {suggestions.map((suggestion) => (
          <Button key={suggestion} variant="outline" size="sm">
            {suggestion}
          </Button>
        ))}
      </ScrollView>
    </View>
  )
}
```

```swift
import EsuissUI
import SwiftUI

struct SuggestionExample: View {
  var body: some View {
    VStack(alignment: .leading, spacing: 12) {
      Text("Try asking").textStyle(.sm).foregroundStyle(EsuissColor.mutedForeground)
      ScrollView(.horizontal, showsIndicators: false) {
        HStack(spacing: 8) {
          ForEach(["Why does the build fail?", "Add dark mode", "Write tests for the cart", "Explain this error"], id: \.self) { suggestion in
            Button(suggestion) {}
              .buttonStyle(.variant(.outline, size: .sm))
          }
        }
      }
    }
  }
}
```

```kotlin
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Button
import com.esuiss.ui.components.ButtonSize
import com.esuiss.ui.components.ButtonVariant
import com.esuiss.ui.components.Text
import com.esuiss.ui.theme.EsuissTheme

@Composable
fun SuggestionAIDefault() {
    Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
        Text("Try asking", color = EsuissTheme.colors.mutedForeground)
        Row(Modifier.horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
            listOf("Why does the build fail?", "Add dark mode", "Write tests for the cart", "Explain this error").forEach {
                Button(it, onClick = {}, variant = ButtonVariant.Outline, size = ButtonSize.Sm)
            }
        }
    }
}
```

Suggestion on mobile is built from the same parts as on the web: [Button](https://suiss.app/ui/docs/components/button). The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

## Installation

**React Native**

```bash title="Terminal"
npx @esuiss/ui@latest add button
```

**SwiftUI**

```bash title="Terminal"
npx @esuiss/ui@latest add button --platform swift
```

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add button --platform kotlin
```

## API Reference

See [Button](https://suiss.app/ui/docs/components/button).

