Building with it
Customising the UI
The overlay is yours to restyle. Set a theme object on init() and Nudge repaints the launcher, the card, the cursor, and the progress bar to match your product.
Everything renders inside a shadow DOM, so the overlay never inherits or leaks your page styles. You change its look through the theme object, not by writing CSS against its internals.
Colours, radius, and type
The three groups you will reach for most. Set only the keys you care about; the rest fall back to sensible defaults.
NudgeSDK.init({
apiKey, apiBase,
theme: {
colors: {
primary: "#e95a20", // buttons, highlight ring
onPrimary: "#ffffff", // text on primary
background: "#ffffff",
surface: "#faf9f5",
text: "#18181b",
textMuted: "#6b7280",
border: "rgba(0,0,0,0.1)",
destructive: "#dc2626",
success: "#15803d",
},
radius: { sm: "6px", md: "10px", lg: "16px", pill: "999px" },
font: {
family: "Inter, system-ui, sans-serif",
sizeMd: "14px",
weightMedium: 500,
weightBold: 600,
},
},
});Contrast
If you changeprimary, set onPrimary to a colour that reads clearly on top of it. A pale label on a pale button is the most common theming mistake.The cursor
The animated pointer that moves to each step's target. You can recolour it, resize it, change its trail, or turn it off entirely.
theme: {
cursor: {
enabled: true,
color: "#e95a20",
ringColor: "rgba(233,90,32,0.3)",
size: 24,
pulse: true,
trail: "comet", // "none" | "line" | "comet"
hideOnMobile: true,
},
}With enabled: false the highlight ring around the target element stays, but the moving pointer is gone. That suits dense interfaces where a flying cursor would feel busy.
The card and progress
The card holds the instruction. The progress bar shows how far through the flow the user is.
theme: {
card: {
width: 320,
placement: "auto", // "auto" | "top" | "bottom" | "left" | "right"
showCloseButton: true,
showProgress: true,
},
progress: { show: true, position: "top", barHeight: 3 },
motion: "snappy", // "subtle" | "snappy" | "off"
shadow: { card: "0 8px 30px rgba(0,0,0,.12)", modal: "0 12px 40px rgba(0,0,0,.2)" },
layout: { z: 2147483600, edgePadding: 16 },
}placement: "auto"lets the card choose a side based on where the target sits in the viewport.motion: "off"removes animation for users who prefer reduced motion or for a calmer feel.layout.zcontrols stacking. Raise it if your own modals cover the overlay.
The launcher label
The floating button reads "Ask your buddy" by default. If you want it gone entirely and prefer to trigger walkthroughs from your own UI, switch the trigger to programmatic mode and call the controller yourself.
const nudge = NudgeSDK.init({
apiKey, apiBase,
trigger: { mode: "programmatic" }, // no floating button
});
nudge.mount();
// later, from your own button:
myHelpButton.addEventListener("click", () => nudge.openInput());Richer customisation in the runtime build
Presets, render slots, and full headless mode (you draw the card yourself) live in the v1 runtime distribution, which is not the package published today. The published SDK gives you thetheme object above, programmatic triggering, and the event stream, which covers most needs. See How it works for the distinction.