Vue Guide
Install
npm install @askable-ui/vue @askable-ui/coreQuick start
<script setup lang="ts">
import { Askable, useAskable } from '@askable-ui/vue';
const { promptContext } = useAskable();
async function ask(question: string) {
return fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({
messages: [
{ role: 'system', content: `UI context: ${promptContext.value}` },
{ role: 'user', content: question },
],
}),
});
}
</script>
<template>
<Askable :meta="{ metric: 'revenue', value: '$128k', period: 'Q3' }">
<RevenueChart />
</Askable>
</template><Askable>
Renders any element (default: div) with data-askable set from :meta.
<!-- Object meta -->
<Askable :meta="{ widget: 'churn-rate', value: '4.2%' }">
<ChurnChart />
</Askable>
<!-- String meta -->
<Askable meta="pricing page hero" as="section">
<HeroSection />
</Askable>Props:
| Prop | Type | Default | Description |
|---|---|---|---|
meta | Record<string, unknown> | string | — | Metadata for the element |
as | string | "div" | HTML element to render |
useAskable(options?)
Composable that connects to the shared global context. Starts observing on mount, cleans up when all consumers unmount.
const { focus, promptContext, ctx } = useAskable();
// focus: Ref<AskableFocus | null>
// promptContext: ComputedRef<string>
// ctx: AskableContext
// Click only
const { focus } = useAskable({ events: ['click'] });
// Inline context options — creates a private context (not the singleton)
const { focus } = useAskable({ maxHistory: 10 });
const { focus } = useAskable({ sanitizeMeta: ({ secret, ...rest }) => rest });When maxHistory, sanitizeMeta, sanitizeText, or textExtractor are provided, a private context is created for that component instead of sharing the global singleton.
Options:
| Option | Type | Description |
|---|---|---|
events | AskableEvent[] | Which events trigger updates. Defaults to ['click', 'hover', 'focus']. |
maxHistory | number | History buffer size. Defaults to 50. Set to 0 to disable. |
sanitizeMeta | (meta) => meta | Redact sensitive metadata keys before storage. |
sanitizeText | (text) => string | Redact sensitive text content before storage. |
textExtractor | (el) => string | Custom text extraction function. |
ctx | AskableContext | Provide a pre-created context (ignores all options above). See below. |
Scoped contexts
By default, useAskable() shares a single global AskableContext across all composable instances on the page. For surfaces that need independent tracking (different event policies, prompt shaping, or redaction rules), pass a pre-created ctx:
import { createAskableContext } from '@askable-ui/core';
import { useAskable } from '@askable-ui/vue';
// Create once, e.g. at the module level or in a parent component
const adminCtx = createAskableContext();
adminCtx.observe(document.getElementById('admin-panel')!);
// In a component that should only track the admin panel
const { focus, promptContext } = useAskable({ ctx: adminCtx });When a scoped ctx is provided, useAskable does not call observe() automatically — you control when and what the context observes. The lifecycle (destroy) is also your responsibility.
Returns:
| Value | Type | Description |
|---|---|---|
focus | Ref<AskableFocus | null> | Reactive current focus |
promptContext | ComputedRef<string> | Reactive prompt-ready context string |
ctx | AskableContext | Underlying context for advanced use |
"Ask AI" button pattern
<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { Askable, useAskable } from '@askable-ui/vue';
const { ctx } = useAskable();
const card = useTemplateRef<HTMLElement>('card');
function askAboutCard() {
ctx.select(card.value!);
openChatPanel();
}
</script>
<template>
<Askable ref="card" :meta="data">
<RevenueChart :data="data" />
<button @click="askAboutCard">Ask AI ✦</button>
</Askable>
</template>Nuxt / SSR
useAskable() is SSR-safe. Observation starts in onMounted() so no DOM access occurs during server render.
// Works in Nuxt without 'use client' / no special config
const { promptContext } = useAskable();