typelessform-widget
v1.0.2
Published
AI-powered voice form filling web component. Fill any HTML form by speaking — React, Vue, Angular, Next.js. Speech-to-text autofill, 25 languages.
Maintainers
Readme
TypelessForm
Free tier available (200 lifetime form fills). Paid plans coming soon.
AI-powered voice form filling. Add <typeless-form> to any page and let users fill forms by speaking.
Watch Demo (YouTube) | Try Live Demo | Get API Key
Quick Start
npm install typelessform-widgetVanilla HTML
<script type="module">
import 'typelessform-widget';
</script>
<typeless-form api-key="YOUR_API_KEY"></typeless-form>React
import 'typelessform-widget';
function App() {
return (
<div>
<h1>My Form</h1>
<form>
<input name="firstName" placeholder="First Name" />
<input name="lastName" placeholder="Last Name" />
<input name="email" type="email" placeholder="Email" />
</form>
{/* @ts-expect-error -- web component */}
<typeless-form api-key="YOUR_API_KEY" />
</div>
);
}Vue
// vite.config.ts
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'typeless-form'
}
}
})
]
});<template>
<form>
<input name="firstName" placeholder="First Name" />
<input name="email" type="email" placeholder="Email" />
</form>
<typeless-form api-key="YOUR_API_KEY" />
</template>
<script setup>
import 'typelessform-widget';
</script>Without the
isCustomElementconfig, Vue will try to resolve<typeless-form>as a Vue component and emit a warning.
Angular
// app.config.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
// schemas: [CUSTOM_ELEMENTS_SCHEMA]
// Import in your main.ts or component
import 'typelessform-widget';<!-- component.html -->
<form>
<input name="firstName" placeholder="First Name" />
<input name="email" type="email" placeholder="Email" />
</form>
<typeless-form api-key="YOUR_API_KEY"></typeless-form>Next.js
This package uses
customElements.define()at import time. Use dynamic import with'use client'to avoid SSR issues.
// src/components/TypelessForm.tsx
'use client';
import { useEffect } from 'react';
export default function TypelessFormLoader() {
useEffect(() => {
import('typelessform-widget');
}, []);
return (
// @ts-expect-error -- web component
<typeless-form api-key="YOUR_API_KEY" />
);
}// src/app/layout.tsx
import TypelessFormLoader from '@/components/TypelessForm';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<TypelessFormLoader />
</body>
</html>
);
}Nuxt.js
// 1. nuxt.config.ts
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag === 'typeless-form'
}
}
})// 2. plugins/typelessform.client.ts
// .client.ts suffix ensures this only runs on client (no SSR)
export default defineNuxtPlugin(() => {
import('typelessform-widget');
});<!-- 3. app.vue -->
<template>
<div>
<NuxtPage />
<typeless-form api-key="YOUR_API_KEY" />
</div>
</template>Placement
Place <typeless-form> directly in <body>, outside any <form> elements. The widget automatically detects all forms on the page.
Never place the widget inside elements with CSS transform (including transform: translateY(0), scroll-reveal animations, etc.) — this breaks position: fixed on the widget's floating button per CSS spec (transforms create a new containing block).
<!-- Correct: in <body>, outside forms -->
<body>
<form>...</form>
<typeless-form api-key="YOUR_API_KEY"></typeless-form>
</body>
<!-- Wrong: inside a form or animated container -->
<form class="reveal"> <!-- has transform -->
<typeless-form api-key="YOUR_API_KEY"></typeless-form>
</form>How It Works
- TypelessForm scans your page for form fields (inputs, selects, textareas)
- User clicks the microphone button and speaks naturally: "My name is John Smith, email [email protected]"
- AI parses the speech and fills matching fields automatically
Getting an API Key
- Visit webappski.com/en/portal
- Sign in with Google
- Copy your API key (starts with
tf_)
Free tier: 200 lifetime form fills, no credit card required.
Supported Fields
| Field Type | Support | | -------------------------- | ------- | | Text inputs | Full | | Email, tel, url | Full | | Date, time, datetime-local | Full | | Number, range | Full | | Textarea | Full |
Configuration
<typeless-form
api-key="YOUR_API_KEY"
></typeless-form>| Attribute | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------- |
| api-key | string | Yes | Your TypelessForm API key (starts with tf_) |
| load-fonts | flag | No | Load bundled Plus Jakarta Sans font. Without this, the widget uses the system font stack (no external requests) |
Position Configuration
By default the widget appears at the bottom-right corner. To change position:
<script>
window.typelessFormConfig = {
position: { bottom: 20, right: 20 }
// position: { bottom: 20, left: 20 }
// position: { top: 20, right: 20 }
};
</script>In frameworks (React, Vue, Angular), set
window.typelessFormConfigin your component before the widget loads (e.g. inuseEffect,onMounted, orngOnInit).
Requirements
- Internet Connection: This widget requires an active internet connection. Form data is processed via TypelessForm's cloud API (hosted in EU, europe-central2).
- Browser Only: This package uses
customElements.define()at import time and is not compatible with server-side rendering. For Next.js/Nuxt.js, use dynamic imports (see examples above).
Content Security Policy (CSP)
Skip this section if your site does not use a
Content-Security-Policyheader. Most sites don't — this only applies if you or your hosting provider have explicitly configured CSP.
If your site does use CSP, the widget will be blocked unless you whitelist our API domain.
Since you install the widget via npm, the JavaScript runs from your own domain — you only need to allow API calls and voice recording:
connect-src https://europe-central2-ai-form-copilot-eu.cloudfunctions.net;
media-src blob:;If you also use the load-fonts attribute, add:
font-src https://ai-form-copilot-eu.web.app;Don't replace your CSP — add to it! The
...below means "your existing directives/domains stay here". Just append our domains after yours.
Important: add our domains to the same place where your CSP is currently configured. A <meta> tag will not override a server-side CSP header.
Below are examples for common configurations. Add font-src line only if you use load-fonts.
HTML <meta> tag
<meta http-equiv="Content-Security-Policy" content="
...
connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net;
media-src ... blob:;
">Nginx
add_header Content-Security-Policy "
...
connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net;
media-src ... blob:;
";Firebase Hosting
{
"headers": [{
"source": "**",
"headers": [{
"key": "Content-Security-Policy",
"value": "... connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net; media-src ... blob:; ..."
}]
}]
}Vercel
{
"headers": [{
"source": "/(.*)",
"headers": [{
"key": "Content-Security-Policy",
"value": "... connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net; media-src ... blob:; ..."
}]
}]
}Netlify
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "... connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net; media-src ... blob:; ..."Apache / .htaccess
<IfModule mod_headers.c>
Header set Content-Security-Policy "\
... \
connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net; \
media-src ... blob:;"
</IfModule>WordPress
function typelessform_csp_header() {
header(
"Content-Security-Policy: "
. "... "
. "connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net; "
. "media-src ... blob:;"
);
}
add_action('send_headers', 'typelessform_csp_header');Cloudflare
Dashboard → Rules → Transform Rules → Response Header:
connect-src ... https://europe-central2-ai-form-copilot-eu.cloudfunctions.net
media-src ... blob:What each directive does
| Directive | Domain | Why |
| ------------- | ---------------------------------------------- | ---------------------------------------------- |
| connect-src | europe-central2-...cloudfunctions.net | API calls (form analysis, voice transcription) |
| media-src | blob: | Voice recording uses in-memory audio blobs |
| font-src | ai-form-copilot-eu.web.app (if load-fonts) | Loads Plus Jakarta Sans web font |
Privacy
- Form fields marked with
data-ai-private="true"are excluded from AI processing - Audio is processed server-side and not stored
- GDPR compliant (EU data processing)
<input name="ssn" data-ai-private="true" placeholder="SSN" />Pricing
| Plan | Price | Form Fills | Status | | -------------- | -------- | ---------------- | --------- | | Pilot | Free | 200 (lifetime) | Available | | Starter | $29/mo | 800/mo | Waitlist | | Professional | $99/mo | 3,000/mo | Waitlist | | Enterprise | $199/mo | 10,000/mo | Waitlist |
Get started with the free Pilot plan at the developer dashboard.
Support
Found a bug or have a feature request? Open an issue on GitHub.
License
MIT
