The share button, but for AI.
The share button, but for AI. You embed a button, craft the prompt, and your visitors copy it or open it directly in Claude, ChatGPT, or Perplexity. One click.
Under 8KB minified + gzipped. Zero dependencies.
Every "Ask AI" widget puts a chatbot on your site. PromptThis does the opposite, it sends your content to the user's own AI provider, with author-crafted prompts that make the AI actually useful. No API keys, no backend, no cost per query. The user gets their preferred tool with their own conversation history.
npm install @promptthis/reactimport { PromptButton } from "@promptthis/react";
import "@promptthis/react/styles.css"; // optional default styles
function Docs({ content }) {
return (
<article>
{content}
<PromptButton
content={content}
role="You are a helpful coding assistant."
openIn={["claude", "chatgpt"]}
/>
</article>
);
}<script src="https://unpkg.com/@promptthis/vanilla@latest/dist/promptthis.global.js"></script>
<div data-prompt="Help me understand this code.">
<h2>Getting Started</h2>
<p>Install the package with npm install acme-sdk...</p>
</div>A button appears on hover. Click it. Pick an AI provider. Done.
| Prop | Type | Default | Description |
|---|---|---|---|
content |
string | RefObject<HTMLElement> |
required | Text or ref to DOM element to extract content from |
role |
string |
- | System role preamble (e.g. "You are a senior developer.") |
context |
string |
- | Additional context prepended before content |
instruction |
string |
- | Instruction appended after content |
openIn |
string[] |
all providers | Filter which AI providers to show ('claude', 'chatgpt', 'perplexity') |
label |
string | null |
'Prompt' |
Button label. Pass null or "" for icon-only |
icon |
ReactNode |
sparkle icon | Custom icon element |
className |
string |
- | Class for the trigger button |
popoverClassName |
string |
- | Class for the popover menu |
style |
CSSProperties |
- | Inline styles for the trigger button (use for CSS variable overrides) |
popoverStyle |
CSSProperties |
- | Inline styles for the popover menu (use for CSS variable overrides) |
copyLabel |
string |
'Copy' |
Label for the copy button in the popover |
onCopy |
(prompt: string) => void |
- | Callback when prompt is copied |
onOpen |
(providerId: string) => void |
- | Callback when an AI provider is opened |
Build your own UI with full control.
import { usePrompt } from "@promptthis/react";
const { prompt, copy, openIn, providers } = usePrompt({
content: "Your text here",
role: "You are a helpful assistant.",
openIn: ["claude", "chatgpt"],
});Returns:
prompt- The assembled prompt stringcopy()- Copy prompt to clipboardopenIn(providerId)- Open prompt in an AI providerproviders- Array of{ id, name, icon }for the filtered providers
Set defaults for all PromptButton and usePrompt instances below it.
import { PromptProvider, PromptButton } from "@promptthis/react";
<PromptProvider
defaultRole="You are a helpful assistant."
openIn={["claude", "chatgpt", "perplexity"]}
>
<App />
</PromptProvider>;Props: openIn, defaultRole, defaultContext, defaultInstruction, customProviders, copyLabel.
| Attribute | Required | Description |
|---|---|---|
data-prompt |
Yes | Marks element as promptable. Value becomes the instruction (empty = default) |
data-prompt-role |
No | System role preamble |
data-prompt-context |
No | Additional context before content |
data-prompt-action |
No | Button label (default: "Prompt"). Set to "" for icon-only |
data-prompt-open-in |
No | Comma-separated provider IDs |
data-prompt-copy-only |
No | Only show "Copy" (no AI provider links) |
<script>
window.PromptThisConfig = {
openIn: ["claude", "chatgpt"],
theme: "dark", // 'light' | 'dark' (default: auto)
label: "Ask AI", // global button label
defaultRole: "You are a helpful assistant.",
defaultContext: "",
defaultInstruction: "", // default instruction for all elements
copyLabel: "Copy", // localize the copy button text
customProviders: [
{
id: "myai",
name: "My AI",
icon: "π€",
url: (prompt) =>
`https://myai.com/chat?q=${encodeURIComponent(prompt)}`,
},
],
};
</script>
<script src="https://unpkg.com/@promptthis/vanilla@latest/dist/promptthis.global.js"></script>// Re-scan after dynamic content loads
PromptThis.init(document.querySelector("#new-content"));
// Clean up
PromptThis.destroy();The React package ships zero CSS by default. Two options:
- Import default styles:
import '@promptthis/react/styles.css' - Style with className:
<PromptButton className="my-btn" popoverClassName="my-menu" />
Default styles live in @layer promptthis, so any Tailwind class or custom CSS overrides them naturally β no !important needed. You can also override with CSS custom properties:
<PromptButton
content="..."
style={
{
"--promptthis-bg": "black",
"--promptthis-text": "white",
"--promptthis-radius": "0px",
"--promptthis-hover-bg": "white",
"--promptthis-hover-text": "black",
} as React.CSSProperties
}
popoverStyle={
{
"--promptthis-popover-bg": "black",
"--promptthis-item-text": "white",
"--promptthis-item-hover-bg": "rgba(255,255,255,0.1)",
} as React.CSSProperties
}
/>Or set variables on any ancestor element:
.my-theme {
--promptthis-bg: black;
--promptthis-text: white;
}Trigger button:
--promptthis-bg, --promptthis-text, --promptthis-border, --promptthis-radius, --promptthis-padding-x, --promptthis-padding-y, --promptthis-gap, --promptthis-font-size, --promptthis-opacity, --promptthis-shadow, --promptthis-hover-bg, --promptthis-hover-text
Popover:
--promptthis-popover-bg, --promptthis-popover-border, --promptthis-popover-radius, --promptthis-popover-shadow
Items:
--promptthis-item-text, --promptthis-item-hover-bg
Dark mode activates automatically via prefers-color-scheme: dark, or manually with a data-theme="dark" attribute on any ancestor:
<div data-theme="dark">
<PromptButton content="..." />
</div>CSS is embedded automatically. Override with CSS custom properties:
:root {
--promptthis-bg: #f5f5f5;
--promptthis-text: inherit;
--promptthis-border: rgba(0, 0, 0, 0.08);
--promptthis-radius: 8px;
--promptthis-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}Add your own AI provider. Use the createProvider helper for a simpler syntax:
import { createProvider } from "@promptthis/core";
const myProvider = createProvider({
id: "myai",
name: "My AI",
icon: "π€",
url: "https://myai.com/chat?q={prompt}", // template string β {prompt} is auto-encoded
});
// Or with a function URL
const myProvider2 = createProvider({
id: "myai",
name: "My AI",
url: (prompt) => `https://myai.com/chat?q=${encodeURIComponent(prompt)}`,
});
// Optional: custom prompt formatting for this provider
const myProvider3 = createProvider({
id: "myai",
name: "My AI",
url: "https://myai.com/chat?q={prompt}",
formatPrompt: (config) => `[${config.content}]\n\nPlease help.`,
});Pass custom providers to PromptProvider or PromptButton:
<PromptProvider customProviders={[myProvider]}>
<App />
</PromptProvider>Custom providers with the same id as a default provider will override it.
<!-- Vanilla -->
<script>
window.PromptThisConfig = {
customProviders: [
{
id: "myai",
name: "My AI",
icon: "π€",
url: (prompt) =>
`https://myai.com/chat?q=${encodeURIComponent(prompt)}`,
},
],
};
</script>Why not just let AI providers browse the page? They can. But an author-crafted prompt will always be better than what an AI extracts on its own. You know the pitfalls, the prerequisites, the ideal way to guide someone. PromptThis lets you encode that knowledge.
How is this different from chatbot widgets? Chatbot widgets run AI on your site. PromptThis sends content to the user's own AI provider. No API keys, no backend, no cost per query. And the user gets to use their preferred tool with their own conversation history.
File size? Under 8KB minified + gzipped. Zero dependencies.
Does this work on mobile? Yes. Bottom sheet on small screens, popover on desktop.
Can I add my own AI provider?
Yes. Pass a customProviders array with id, name, icon, and url function. See "Custom Providers" above.
| Package | Description |
|---|---|
@promptthis/core |
Pure TypeScript logic: prompt assembly, providers, clipboard |
@promptthis/react |
React components: PromptButton, usePrompt, PromptProvider |
@promptthis/vanilla |
Vanilla script tag drop-in: auto-init, embedded CSS |
Uses Changesets for versioning and publishing. All packages share the same version number (fixed mode).
# 1. After making changes, create a changeset
npx changeset
# Interactive prompt: which packages changed? patch/minor/major? summary?
# 2. When ready to release, apply version bumps + generate CHANGELOGs
npm run version
# 3. Publish to npm (clean β build β test β publish)
npm run releaseChangesets automatically handles:
- Bumping all packages to the same version (fixed mode)
- Updating internal
@promptthis/coredependency in react and vanilla - Publishing in dependency order (core β react β vanilla)
- Generating
CHANGELOG.mdfor each package
Publishing is automated via GitHub Actions with npm Trusted Publishing (OIDC) β no tokens needed. After merging to main, a "Version Packages" PR is created automatically. Merging that PR triggers the publish.
Run the interactive demo locally:
npm run demoOpens a Next.js app at localhost:3000 with live examples of PromptButton, usePrompt hook, and PromptProvider.
MIT