Skip to content

Inspector / Dev Panel

createAskableInspector mounts a floating overlay panel on the page that shows what Askable is currently tracking — useful for development and for creating demos.

The panel also shows registered context sources, so you can confirm that app-owned sources such as tables, documents, charts, or MCP bridges are mounted and refreshing while you test interactions.

Use the Copy action in the header to copy the exact prompt context currently shown in the panel.

What it shows

The panel updates in real time whenever the focused element changes:

┌─────────────────────────────────────────────┐
│ ✦ Askable Inspector                         │
├─────────────────────────────────────────────┤
│ Element                                     │
│   div#revenue-card.widget-card              │
│                                             │
│ Meta                                        │
│   {                                         │
│     metric: "revenue",                      │
│     value: "$2.3M",                         │
│     delta: "+12%"                           │
│   }                                         │
│                                             │
│ Text                                        │
│   Revenue: $2.3M                            │
│                                             │
│ Prompt context                              │
│   User is focused on: — metric: revenue,    │
│   value: $2.3M, delta: +12% — value         │
│   "Revenue: $2.3M"                          │
└─────────────────────────────────────────────┘

Quick start

ts
import { createAskableContext, createAskableInspector } from '@askable-ui/core';

const ctx = createAskableContext();
ctx.observe(document);

// Mount the inspector — only do this in development
if (process.env.NODE_ENV === 'development') {
  createAskableInspector(ctx);
}

Options

ts
createAskableInspector(ctx, {
  position: 'bottom-right',  // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
  highlight: true,           // outline the focused element
  tools: true,               // buttons for region, circle, lasso, text, and clear
  sourcePreview: true,       // include registered source data in preview/copy
  promptOptions: {           // forwarded to toPromptContext()
    preset: 'compact',
  },
});
OptionTypeDefaultDescription
positionstring'bottom-right'Where to anchor the panel
highlightbooleantrueDraw an outline on the focused element
toolsbooleantrueShow buttons for region, circle, lasso, text selection, and clear
promptOptionsAskablePromptContextOptionsOptions for the prompt output preview
sourcePreviewboolean | AskableInspectorSourcePreviewOptionsfalseResolve app-owned sources into the preview and Copy output

Use sourcePreview when you want the inspector to show the same source-backed context a chat bridge receives from toPromptContextAsync().

ts
createAskableInspector(ctx, {
  sourcePreview: {
    sources: [{ id: 'accounts', mode: 'all', maxItems: 20 }],
    sourceErrorMode: 'include',
  },
});

React

tsx
// components/DevInspector.tsx
'use client';
import { AskableInspector, useAskable } from '@askable-ui/react';

export function DevInspector() {
  useAskable({ events: ['click'] });

  if (process.env.NODE_ENV !== 'development') return null;
  return <AskableInspector events={['click']} position="bottom-left" />;
}
tsx
// app/layout.tsx
import { DevInspector } from '@/components/DevInspector';

export default function Layout({ children }) {
  return (
    <>
      {children}
      {process.env.NODE_ENV === 'development' && <DevInspector />}
    </>
  );
}

If your React app uses a custom ctx, name, events, or viewport setting, pass the same values to <AskableInspector /> so the panel follows the same context instead of falling back to the default click/hover/focus observer.

tsx
const ctx = createAskableContext();
ctx.observe(document, { events: ['click'] });

function DevInspector() {
  useAskable({ ctx });
  return process.env.NODE_ENV === 'development'
    ? <AskableInspector ctx={ctx} />
    : null;
}

Vue

vue
<!-- components/DevInspector.vue -->
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { createAskableInspector } from '@askable-ui/core';
import { useAskable } from '@askable-ui/vue';

const { ctx } = useAskable();
let handle: { destroy(): void } | null = null;

onMounted(() => {
  if (import.meta.env.DEV) {
    handle = createAskableInspector(ctx, { position: 'bottom-left' });
  }
});
onUnmounted(() => handle?.destroy());
</script>

<template></template>

Cleanup

createAskableInspector returns a handle object with a destroy() method:

ts
const inspector = createAskableInspector(ctx);

// Remove the panel and detach all listeners
inspector.destroy();

Calling createAskableInspector again while a panel is already visible replaces the existing panel — you won't end up with multiple overlays.

Guards

Always guard the inspector behind a development check so it never ships to production:

ts
// Vite / Next.js
if (import.meta.env.DEV) {
  createAskableInspector(ctx);
}

// Node environment variable
if (process.env.NODE_ENV === 'development') {
  createAskableInspector(ctx);
}

Released under the MIT License.