Syed Hasnain

Edit Message

Component 1

About

A user message with copy and edit actions, inline editing with keyboard shortcuts, and switching between edited versions.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Edit Message to your project and fits it to your theme.

Code

How Edit Message is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import * as React from 'react'
import { EditMessage } from '@/components/ui/edit-message'

const original = 'Focus the next collection on conversation recovery.'
const revised = 'Focus the next collection on conversation recovery and keyboard navigation.'
const extra = revised.slice(original.length - 1)

type Phase = 'idle' | 'editing' | 'saved'

export default function Demo() {
  const [phase, setPhase] = React.useState<Phase>('editing')
  const [typed, setTyped] = React.useState(12)
  const [versions, setVersions] = React.useState([original])
  const [active, setActive] = React.useState(0)
  const [draft, setDraft] = React.useState(original.slice(0, -1) + extra.slice(0, 12))
  const [auto, setAuto] = React.useState(true)

  React.useEffect(() => {
    if (!auto) return
    if (phase === 'editing' && typed < extra.length) {
      const timer = setTimeout(() => {
        setTyped((value) => value + 1)
        setDraft(original.slice(0, -1) + extra.slice(0, typed + 1))
      }, 45)
      return () => clearTimeout(timer)
    }
    const timer = setTimeout(
      () => {
        if (phase === 'idle') {
          setDraft(original)
          setTyped(0)
          setPhase('editing')
        } else if (phase === 'editing') {
          setVersions([original, revised])
          setActive(1)
          setPhase('saved')
        } else {
          setVersions([original])
          setActive(0)
          setPhase('idle')
        }
      },
      phase === 'saved' ? 3600 : phase === 'idle' ? 1600 : 700,
    )
    return () => clearTimeout(timer)
  }, [auto, phase, typed])

  return (
    <div className="w-full max-w-lg" onPointerDown={() => setAuto(false)}>
      <EditMessage
        activeVersion={active}
        draft={draft}
        editing={phase === 'editing'}
        onActiveVersionChange={setActive}
        onDraftChange={setDraft}
        onEditingChange={(editing) => setPhase(editing ? 'editing' : 'saved')}
        onSave={(value) => setVersions((current) => [...current, value])}
        versions={versions}
      />
    </div>
  )
}

Dependencies

More by Syed Hasnain

View all
  • Color Picker

    Color Picker

    110
  • Cost Meter

    Cost Meter

    34
  • Message Scroller

    Message Scroller

    28
  • Background Inbox

    Background Inbox

    26
  • Quota Banner

    Quota Banner

    25
  • Commit

    Commit

    23
  • Attachments

    Attachments

    22
  • Image Generation Loader

    Image Generation Loader

    19

Explore more

Part of Pasta UI — browse the full library on 21st.dev.