suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
  • AI
GitHubCreate
DocsComponentsPatternsInteractionsChartsBlocksAICreate
AI21
  • Overview
Conversation
  • Chat
  • Message
  • Prompt Input
  • Suggestion
  • Model Selector
  • Context
  • Checkpoint
  • Inline Citation
Agent steps
  • Chain of Thought
  • Reasoning
  • Tool
  • Confirmation
  • Task
  • Plan
  • Queue
  • Subagent
  • Sources
Output
  • Terminal
  • Stack Trace
  • Test Results
  • File Tree

suiss/ui · AI

Inline Citation

A source link inside the sentence it supports, with a preview of the page on hover.

import { buttonVariants } from "@/components/ui/button"
import {
  HoverCard,
  HoverCardContent,
  HoverCardTrigger,
} from "@/components/ui/hover-card"

type Source = {
  url: string
  title: string
  description: string
}

const sources = {
  streaming: {
    url: "https://nextjs.org/docs/app/getting-started/linking-and-navigating#streaming",

Inline Citation is a source that sits in the sentence it supports. The trigger is a link to the source, styled as a small Button, and a Hover Card previews its title and description.

To show a list of sources after the reply, use Sources.

Installation

Inline Citation is built with the Hover Card and Button components.

$ pnpm dlx shadcn@latest add @esuiss/hover-card @esuiss/button

Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add hover-card button

Usage

<HoverCard>
  <HoverCardTrigger
    href={url}
    target="_blank"
    rel="noreferrer"
    className={buttonVariants({ variant: "secondary", size: "xs" })}
  >
    {hostname}
    <span className="sr-only"> (opens in a new tab)</span>
  </HoverCardTrigger>
  <HoverCardContent className="flex w-64 flex-col gap-1 text-sm">
    <div className="font-medium">{title}</div>
    <p className="text-muted-foreground">{description}</p>
  </HoverCardContent>
</HoverCard>

AI SDK

A source-url part is the citation. Set sendSources: true on toUIMessageStreamResponse(), or write the part yourself.

app/api/chat/route.ts
writer.write({
  type: "source-url",
  sourceId: "suiss",
  url: "https://suiss.app/ui",
  title: "suiss/ui",
})
const sources = message.parts.filter((part) => part.type === "source-url")

title is optional. Fall back to the URL's hostname.

API Reference

See Hover Card and Button.

Accessibility

  • The trigger is a real link, so the source opens with a click or Enter, and the preview opens on focus as well as on hover.
  • Add "(opens in a new tab)" to the link text with sr-only.
  • The hover card repeats what the link names, so readers who cannot hover lose nothing.
import { View } from "react-native"
import { Button } from "@/components/ui/button"
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from "@/components/ui/popover"
import { Text } from "@/components/ui/text"

export function AiInlineCitationExample() {
  return (
    <View className="w-full gap-2">
      <Text>
        Suspense shows a fallback until its children finish loading, so the page
        can stream the rest of the content first.
      </Text>
      <View className="items-start">
        <Popover>
          <PopoverTrigger render={<Button variant="secondary" size="xs" />}>
            <Text>react.dev</Text>
import EsuissUI
import SwiftUI

struct InlineCitationExample: View {
  @State private var open = false

  var body: some View {
    VStack(alignment: .leading, spacing: 8) {
      Text("Suspense shows a fallback until its children finish loading, so the page can stream the rest of the content first.")
        .textStyle(.base)
        .foregroundStyle(EsuissColor.foreground)
      Button("react.dev") { open = true }
        .buttonStyle(.variant(.secondary, size: .xs))
        .popover(isPresented: $open) {
          PopoverContent(width: 288) {
            PopoverHeader {
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
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.Popover
import com.esuiss.ui.components.PopoverDescription

Inline Citation on mobile is built from the same parts as on the web: Popover, Button. The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

Installation

$ pnpm dlx @esuiss/ui@latest add popover button
$ pnpm dlx @esuiss/ui@latest add popover button --platform swift
$ pnpm dlx @esuiss/ui@latest add popover button --platform kotlin

API Reference

See Popover, Button.

NextChain of ThoughtPreviousCheckpoint

On this page

  1. 01Installation
  2. 02Usage
  3. 03AI SDK
  4. 04API Reference
  5. 05Accessibility
  6. 06Installation
  7. 07API Reference