npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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-widget

Vanilla 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 isCustomElement config, 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

  1. TypelessForm scans your page for form fields (inputs, selects, textareas)
  2. User clicks the microphone button and speaks naturally: "My name is John Smith, email [email protected]"
  3. AI parses the speech and fills matching fields automatically

Getting an API Key

  1. Visit webappski.com/en/portal
  2. Sign in with Google
  3. 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.typelessFormConfig in your component before the widget loads (e.g. in useEffect, onMounted, or ngOnInit).

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-Policy header. 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