Customization

Navieo is designed to be flexible. Here are the main ways to customize its behavior.

Suggestion Chips

Configure the suggestion chips shown when the chat is empty:

<NavieoProvider
  suggestions={[
    { label: "How do I create a project?" },
    { label: "Where are billing settings?", tag: "Popular" },
    { label: "How do I invite my team?", tag: "New" },
    { label: "How do I export data?" },
  ]}
>
  {children}
</NavieoProvider>

Each suggestion can have an optional tag that renders as a small colored badge next to the label.

Chat Modes

The widget includes a mode selector at the bottom-left of the chat input. Users can switch between:

  • Ask — Text Q&A. Returns answers without launching visual tours.
  • Guide — Step-by-step visual walkthroughs (default mode).

You can set the mode programmatically:

const { chatMode, setChatMode } = useNavieo();

// Switch to Ask mode for text-only answers
setChatMode("ask");

The selected mode persists in sessionStorage across page navigation.

Hiding the Widget per Route

Use the showWidget prop to hide the chat widget on specific pages:

"use client";
import { NavieoProvider } from "@navieo/react";
import { usePathname } from "next/navigation";

const HIDDEN_ROUTES = ["/login", "/signup", "/onboarding"];

export function Providers({ children }) {
  const pathname = usePathname();
  const showWidget = !HIDDEN_ROUTES.includes(pathname);

  return (
    <NavieoProvider showWidget={showWidget}>
      {children}
    </NavieoProvider>
  );
}

SPA Navigation

For single-page apps, pass your router's push function to enable smooth client-side navigation during tours:

// Next.js
<NavieoProvider onNavigate={(route) => router.push(route)}>

// React Router
<NavieoProvider onNavigate={(route) => navigate(route)}>

If omitted, Navieo falls back to window.location.href which works but causes a full page reload.

Cross-Page Tours

Navieo handles multi-page tours automatically. When a tour step requires navigating to a different route:

  1. The provider calls your onNavigate callback (or falls back to window.location.href)
  2. It waits for the route change to complete
  3. After a brief delay for the page to render, it continues the tour on the new page

This works seamlessly with Next.js client-side navigation.

Tour Controls

Use the hook to programmatically control tours:

const { startTour, endTour, nextStep, prevStep, goToStep } = useNavieo();

// Start a tour programmatically
await startTour("How do I set up notifications?");

// Navigate through steps
nextStep();
prevStep();
goToStep(3);

// End the tour early
endTour();

Triggering Tours from UI Elements

You can create custom trigger buttons anywhere in your app:

function HelpButton() {
  const { startTour } = useNavieo();

  return (
    <button onClick={() => startTour("How do I use this feature?")}>
      Need help?
    </button>
  );
}

Triggering Chat Open/Close

function NavBar() {
  const { openChat, closeChat, toggleChat, isChatOpen } = useNavieo();

  return (
    <nav>
      <button onClick={toggleChat}>
        {isChatOpen ? "Close Help" : "Get Help"}
      </button>
    </nav>
  );
}

Theming

The chat widget supports full visual customization via the theme prop. Use "dark" or "light" presets, or pass custom color variables. See the Themes page for the full reference.

<NavieoProvider theme="dark">
  {children}
</NavieoProvider>

Element Selectors Best Practices

Navieo finds UI elements using standard CSS selectors. No special attributes are required — but the right selector strategy makes tours significantly more reliable.

Add IDs to key elements

The simplest and most reliable approach. Add id attributes to the elements you want Navieo to highlight:

<button id="create-project" onClick={handleCreate}>Create Project</button>
<div id="billing-section">
  <h2>Billing</h2>
  ...
</div>

Then reference them in your sitemap:

{
  "id": "create-project",
  "type": "button",
  "selector": { "cssSelector": "#create-project" },
  "description": "Button to create a new project"
}

IDs are unique per page, fast to look up, and survive layout changes. You only need them on the 5-15 elements per page that tours will reference.

Navigation links already have unique href attributes — no changes needed:

{ "cssSelector": "aside a[href='/settings']" }
{ "cssSelector": "nav a[href='/dashboard']" }
{ "cssSelector": "header a[href='/docs']" }

Avoid fragile selectors

These work but will break easily:

// Bad -- breaks if you add a section above it
{ "cssSelector": "main > div:nth-child(3)" }

// Bad -- breaks with any styling change
{ "cssSelector": ".bg-blue-600.text-white.rounded-lg" }

// Bad -- breaks if text content changes
{ "cssSelector": "button:first-of-type" }

Summary

DoDon't
#create-projectdiv > div:nth-child(3) > button
a[href='/settings'].bg-blue-600.text-white
#installationmain > section:nth-of-type(2)
[aria-label='Close']button:first-of-type