askable-ui

askable-ui

Two lines of code to give your LLM eyes.
One attribute. Zero prompt engineering. It knows exactly what the user sees.

npm version npm downloads MIT license CI PRs welcome

Quick Start  ·  Why  ·  How it works  ·  Works with  ·  Features  ·  Packages  ·  Docs  ·  Live Demo


Quick start

npm install @askable-ui/react
import { Askable, useAskable } from '@askable-ui/react';

function Dashboard({ kpi }) {
  const { promptContext } = useAskable();
  // promptContext: "User is focused on: metric=revenue, value=$2.3M, delta=+12%"

  return (
    <Askable meta={{ metric: kpi.name, value: kpi.value, delta: kpi.delta }}>
      <KPICard data={kpi} />
    </Askable>
  );
}

That's it. promptContext updates automatically as the user interacts. Pass it to any LLM.


Why

AI copilots ask users to describe what they're looking at. That's friction — and it's imprecise.

askable-ui solves this with one HTML attribute. Mark any element with data-askable, and the library tracks user focus and serializes it into a prompt-ready string. The model gets the user's exact visual context — not a guess, the real thing.

No page scraping. No DOM serialization. No prompt bloat. Lightweight and zero-dependency.


How it works

1. Annotate — same data that renders your chart feeds the AI

<Askable meta={{ metric: 'revenue', value: '$2.3M', delta: '+12%', period: 'Q3' }}>
  <RevenueChart data={data} />
</Askable>

2. Observe — automatic, zero config

const { ctx, promptContext } = useAskable();
// promptContext updates whenever the user clicks, hovers, or focuses

const { ctx: tableCtx } = useAskable({ name: 'table' });
const { ctx: chartCtx } = useAskable({ name: 'chart' });
// named contexts stay isolated for multi-region pages

const { ctx: screenCtx } = useAskable({ viewport: true });
// screenCtx.toViewportContext() serializes currently visible annotated elements

3. Inject — at the AI boundary, one line

const result = await streamText({
  model: openai('gpt-4o'),
  system: `You are a helpful analytics assistant.\n\n${promptContext}`,
  messages,
});

Works with

LLM SDKs — OpenAI · Anthropic · Vercel AI SDK · CopilotKit · LangChain · any SDK

Frameworks — React · Vue 3 · Svelte · Vanilla JS · Next.js · Nuxt · SvelteKit

askable-ui is the context layer. It doesn't replace your LLM SDK — it gives it eyes.


Features

  • Zero config — one attribute, works with any DOM structure, styling system, or component library
  • React, Vue, Svelte — idiomatic hooks and components; core is framework-agnostic
  • SSR safe — defers to client lifecycle, no window is not defined
  • "Ask AI" buttonctx.select(element) pins focus to any element programmatically
  • Conversation historyctx.toHistoryContext(n) for multi-turn context
  • Viewport awarenessctx.getVisibleElements() / ctx.toViewportContext() for on-screen context
  • Redaction hooks — strip sensitive fields before data reaches serialization
  • Inspector panel<AskableInspector /> or useAskable({ inspector: true }) for a live dev overlay
  • Lightweight core — zero runtime dependencies

Packages

Package Version Use when
@askable-ui/core Vanilla JS, custom framework, or as a peer dep
@askable-ui/react React 18+
@askable-ui/react-native React Native (initial press-driven adapter)
@askable-ui/vue Vue 3
@askable-ui/svelte Svelte 4 & 5
Framework quick starts

React Native

npm install @askable-ui/react-native
import { Pressable, Text } from 'react-native';
import { Askable, useAskable } from '@askable-ui/react-native';

function RevenueCard() {
  const { ctx, promptContext } = useAskable();

  return (
    <Askable ctx={ctx} meta={{ widget: 'revenue' }} text="Revenue card">
      <Pressable>
        <Text>Revenue</Text>
      </Pressable>
    </Askable>
  );
}

For a runnable mobile demo, see examples/react-native-expo.

Vue 3

npm install @askable-ui/vue
<script setup>
import { Askable, useAskable } from '@askable-ui/vue';
const { promptContext } = useAskable();
const props = defineProps(['kpi']);
</script>

<template>
  <Askable :meta="{ metric: kpi.name, value: kpi.value }">
    <KPICard :data="kpi" />
  </Askable>
</template>

Svelte

npm install @askable-ui/svelte
<script>
  import { Askable, useAskable } from '@askable-ui/svelte';
  const { promptContext } = useAskable();
  export let kpi;
</script>

<Askable meta={{ metric: kpi.name, value: kpi.value }}>
  <KPICard data={kpi} />
</Askable>

Vanilla JS

npm install @askable-ui/core
import { createAskableContext } from '@askable-ui/core';

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

ctx.on('focus', () => {
  console.log(ctx.toPromptContext());
  // "User is focused on: — metric: revenue, value: $2.3M"
});


Documentation

askable-ui.com/docs

Guide
Getting started Install, observe, inject
Annotating elements data-askable, nesting, priority
React · Vue · Svelte Framework guides
CopilotKit integration Context-in-input pattern
API reference Full type docs

Contributing

PRs welcome! See CONTRIBUTING.md for setup instructions.

License

MIT — see LICENSE

Top categories

Loading Svelte Themes