Add an AI-powered prompt interface to your website in minutes.
Add these lines to your HTML:
<div id="nova-widget"></div>
<script src="https://embeded.nova.webpros.com/latest/nova-embedded.umd.js"></script>
<script>
NovaPrompt({
target: '#nova-widget',
onSend: async (prompt) => {
// Handle the submitted prompt
console.log('User prompt:', prompt);
}
});
</script>
That's it! The widget will render in the #nova-widget container. Styles are bundled into the JS file — no separate CSS <link> is needed.
For production environments, we recommend pinning to a specific version instead of using latest:
<script src="https://embeded.nova.webpros.com/v1.1.0/nova-embedded.umd.js">
| Option | Type | Description |
|---|---|---|
target |
string |
CSS selector for the container element |
onSend |
function |
Called when the user submits a prompt. Receives the prompt text (base64 encoded by default). |
| Option | Type | Default | Description |
|---|---|---|---|
locales |
object |
See below | Customize UI text |
showExamples |
boolean |
true |
Show example prompts below the input |
showLogo |
boolean |
true |
Show the Nova logo above the title |
examples |
array |
Default examples | Custom example prompts (max 3 shown) |
placeholders |
array |
Default placeholders | Custom placeholder text options |
encodeOnSend |
boolean |
true |
Base64 encode the prompt before calling onSend |
onBeforeSend |
function |
— | Hook to validate or modify the prompt before sending |
showLogs |
boolean |
false |
Enable console logging for debugging |
logger |
function |
console.log |
Custom log function used when showLogs is true |
Override any UI text using the locales option:
NovaPrompt({
target: '#nova-widget',
locales: {
title: 'Build Your Dream Website',
description: 'Describe what you want to create and we\'ll build it for you.',
sendButton: 'Create Now',
sendButtonLoading: 'Creating...', // shown while submission is in progress
explorePrompts: 'Try these ideas',
placeholderPrefix: 'Describe your'
},
onSend: async (prompt) => { /* ... */ }
});
| Key | Default | Description |
|---|---|---|
title |
'All it takes is a conversation' |
Heading above the input |
description |
'Describe your idea…' |
Subheading below the title |
sendButton |
'Start Building' |
Submit button label |
sendButtonLoading |
null |
Button label while loading; falls back to sendButton when not set |
explorePrompts |
'Explore prompts' |
Label before the example prompts list |
placeholderPrefix |
'Ask to create' |
Prefix used in rotating placeholder text |
Display your own example prompts to inspire users:
NovaPrompt({
target: '#nova-widget',
examples: [
{
title: 'Online Store',
prompt: 'Create a modern e-commerce site with product catalog and shopping cart'
},
{
title: 'Portfolio',
prompt: 'Build a creative portfolio website with project gallery and contact form'
},
{
title: 'Blog',
prompt: 'Design a clean blog with categories, search, and newsletter signup'
}
],
onSend: async (prompt) => { /* ... */ }
});
Use onBeforeSend to validate input, authenticate users, or modify the prompt before submission:
NovaPrompt({
target: '#nova-widget',
onBeforeSend: async (prompt) => {
// Ensure user is logged in
if (!currentUser) {
openLoginModal();
throw new Error('Login required'); // Cancels submission
}
// Optionally modify the prompt
return `[Source: Partner Site] ${prompt}`;
},
onSend: async (prompt) => {
await fetch('/api/process', {
method: 'POST',
body: JSON.stringify({ prompt })
});
}
});
The widget renders inside a Shadow DOM, which means host-page styles cannot accidentally leak in. There are two supported ways to customize the appearance.
CSS custom properties defined on the host element (or :root) are inherited by the Shadow DOM. Set them on the container element or any ancestor:
#nova-widget {
/* Primary accent color */
--primary: oklch(0.53 0.278 298.33);
/* Border radius */
--radius: 0.625rem;
/* Font */
--default-font-family: system-ui, sans-serif;
/* Text sizes */
--text-leading: 3rem;
--text-base: 1rem;
/* Input border gradient */
--border-gradient: linear-gradient(
150deg,
var(--color-cyan-400) -15%,
var(--color-purple-500) 45%,
var(--color-pink-400) 85%,
var(--color-orange-500) 100%
);
/* Flat border color (used when --border-gradient is overridden to none) */
--border: #eee;
}
::part() SelectorsKey elements expose named parts that can be styled from outside the Shadow DOM using ::part():
| Part name | Element |
|---|---|
title |
Heading text |
description |
Description text |
textarea |
Prompt input field |
textareaWrapper |
Container wrapping the textarea |
submitButton |
Send button |
submitButtonIcon |
Icon inside the send button |
examples |
Example prompts container |
exampleButton |
Individual example prompt buttons |
/* Example: custom submit button and hidden icon */
#nova-widget::part(submitButton) {
background: salmon;
}
#nova-widget::part(submitButtonIcon) {
display: none;
}
#nova-widget::part(exampleButton) {
background: pink;
border: 1px solid salmon;
}
#nova-widget::part(title),
#nova-widget::part(description) {
color: darkred;
}
If you prefer ES modules:
<div id="nova-widget"></div>
<script type="module">
import { NovaPrompt } from 'https://embeded.nova.webpros.com/latest/nova-embedded.es.js';
NovaPrompt({
target: '#nova-widget',
onSend: async (prompt) => {
// Handle submission
}
});
</script>
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="nova-widget"></div>
<style>
/* Customize via CSS variables */
#nova-widget {
--primary: #7c3aed;
}
/* Customize specific parts via ::part() */
#nova-widget::part(submitButton) {
border-radius: 9999px;
}
</style>
<script src="https://embeded.nova.webpros.com/v0.0.1/nova-embedded.umd.js"></script>
<script>
NovaPrompt({
target: '#nova-widget',
locales: {
title: 'What would you like to build?',
sendButton: 'Get Started',
sendButtonLoading: 'Starting...'
},
examples: [
{ title: 'Landing Page', prompt: 'Create a startup landing page with hero section and pricing' },
{ title: 'Dashboard', prompt: 'Build an analytics dashboard with charts and data tables' },
{ title: 'Booking Site', prompt: 'Design a restaurant booking system with calendar and reservations' }
],
onSend: async (encodedPrompt) => {
const response = await fetch('https://your-api.com/prompts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: encodedPrompt })
});
if (response.ok) {
window.location.href = '/builder';
}
}
});
</script>
</body>
</html>
showLogo option — New boolean option (default true) to control whether the Nova logo is displayed above the title. The entire header block (logo, title, description) is now hidden when all three are absent.Style isolation — The widget no longer inherits styles from your page. Your global CSS resets, font rules, and component styles won't affect the widget, so it will look consistent regardless of where it's embedded.
Customize specific elements with ::part() — You can now target individual widget elements from your own CSS using ::part() selectors. This replaces the need to fight specificity with class overrides:
#nova-widget::part(submitButton) { background: salmon; }
#nova-widget::part(submitButtonIcon) { display: none; }
#nova-widget::part(exampleButton) { background: pink; }
#nova-widget::part(title) { color: darkred; }
#nova-widget::part(description) { color: darkred; }
Available parts: title, description, textarea, textareaWrapper, submitButton, submitButtonIcon, examples, exampleButton.
locales.sendButtonLoading — New locale option to show a custom label on the submit button while a request is in progress (e.g. "Sending..."). Falls back to sendButton text when not set.
The CSS <link> tag is no longer needed. Styles are now bundled inside the JS file. You can safely remove the <link rel="stylesheet" href="...nova-embedded.css"> line from your page.
CSS variable overrides must now be set on the widget container (or a parent), not on :root. The widget no longer reads CSS variables from :root.
/* Before */
:root { --primary: purple; }
/* After */
#nova-widget { --primary: purple; }