Prompt Showcase
A self-playing prompt box React component for marketing pages. A glowing pill types out a prompt, a fake cursor glides in and clicks send, and a result card pops up, on loop, pausing on hover.
A "watch it run itself" showcase for product heroes and feature sections. You provide a script (each item is a prompt string plus the content of a result card) and the component performs it in order: a pill with a glowing border types the prompt out character by character with a blinking caret; then a fake cursor glides in from outside the bottom-right, clicks the send button, which squishes and turns into a small spinner; a result card springs up from below, holds for a while, fades out, and the next item begins. The component is display-only and cannot be typed into; it only plays while in view and pauses when the pointer hovers it.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add prompt-showcase.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<PromptShowcase/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/prompt-showcase.en.jsonOr, once registries are configured in components.json, install it as @webberui/prompt-showcase.
Usage
import { PromptShowcase } from "@/components/ui/prompt-showcase";
<PromptShowcase
script={[
{
prompt: "幫我把這週的會議紀錄整理成三點重點",
result: (
<ol className="list-decimal pl-5">
<li>官網改版延到 11 月中上線</li>
<li>客服回覆時間目標縮短為 4 小時</li>
<li>下週三前確認秋季活動預算</li>
</ol>
),
},
{
prompt: "為手作甜點店寫一句秋季新品標語",
result: <p>「栗子落下的季節,甜一口剛剛好。」</p>,
delayMs: 3200,
},
]}
placeholder="問小幫手任何事…"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
script | PromptShowcaseItem[] | — | The script: each prompt/result pair is played in order |
value | number | — | Controlled index of the current script item; when omitted the component manages it (uncontrolled) |
defaultValue | number | 0 | Starting script index in uncontrolled mode |
onChange | (index: number) => void | — | Called when moving to the next script item, with the new index |
charMs | number | 40 | Typing interval per character (ms) |
delayMs | number | 2600 | Default result card hold time (ms); a script item's delayMs overrides it |
glow | number | 0.6 | Opacity of the outer glow layer (0–1) |
loop | boolean | true | Whether to start over after the last item; when false it stops on the last result |
autoPlay | boolean | true | Whether to auto-play; only plays while in view. When false the current item's full result is shown |
pauseOnHover | boolean | true | Pause the show while the pointer hovers |
placeholder | string | "Ask anything…" | Grey placeholder shown before typing starts |
sendLabel | string | "Send" | Accessible name of the send button |
label | string | "Prompt showcase" | Accessible name of the whole showcase (figure) |
className | string | — | Forwarded to the outer figure |
PromptShowcaseItem
| Field | Type | Default | Description |
|---|---|---|---|
prompt | string | — | Prompt text typed out character by character |
result | ReactNode | — | Content of the result card that pops up after sending |
delayMs | number | — | How long the result card stays (ms); falls back to the component's delayMs |
How it works
- One round: the pill rests for 300ms → the prompt is typed out (
charMsper character) → a 250ms pause → the fake cursor glides to the send button over 600ms withcubic-bezier(0.23,1,0.32,1)→ a 160ms click squish, and the send button shows a spinner for 400ms → the result card springs in (stiffness 320, damping 26) → it holds fordelayMs→ a 200ms fade-out, then the next item. - Typing splits characters with
Array.from, so each CJK character is one step and emoji are never cut in half. - The glowing border registers an angle variable with CSS
@property --wb-ps-angle, so keyframes can rotate theconic-gradientstart angle; browsers without@propertyfall back to a static gradient border. - Override the look with CSS variables:
--wb-ps-glow-1(default#60a5fa),--wb-ps-glow-2(default#a78bfa),--wb-ps-glow-period(one full rotation, default3s) and--wb-ps-fade(text fade-out, default200ms); the component also writescharMsto--wb-ps-char-msfor your own styles to reference. - The result area stacks invisible copies of every result in one grid cell to reserve the tallest height, so the layout never jumps while looping.
- Pausing (hover or scrolling out of view) only halts the scheduler; on resume it continues from the current stage instead of retyping from the start.
Accessibility
- The outer element is a
figurewith anaria-label(notrole="img"), so the result card content stays readable by screen readers - The text being typed is hidden from assistive technology; the full prompt is provided as
sr-onlytext, so it is not read out one character at a time - The result area is
aria-live="polite", so each new result card is announced - The attachment icon, send button and fake cursor are decorative:
aria-hiddenandtabIndex={-1}, they never take focus and cannot be clicked; the pointer is only used to trigger pausing - When the user has reduce motion enabled at the system level, nothing is typed, the cursor does not move and the border does not rotate; the current item's full prompt and result card are shown directly, with no looping
Feature Compare Matrix
A plan feature comparison table with a sticky first column and header, highlighted difference rows, and animated checks and crosses.
Integration Connect Grid
A React component where integration cards drop into a grid in sequence, then flip one by one to a connected state with a drawn checkmark. Autoplay it as a showcase, or let users click to connect and await async authorization.