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 🙏

© 2025 – Pkg Stats / Ryan Hefner

dictate-button

v1.9.0

Published

Customizable Web Component that adds speech-to-text dictation capabilities to text fields

Readme

Dictate Button

NPM Version Tests

A customizable web component that adds speech-to-text dictation capabilities to any text input, textarea field, or contenteditable element on your website.

Developed for dictate-button.io.

Features

  • Easy integration with any website
  • Compatible with any framework (or no framework)
  • Automatic injection into text fields with the data-dictate-button-on attribute (exclusive mode) or without the data-dictate-button-off attribute (inclusive mode)
  • Simple speech-to-text functionality with clean UI
  • Customizable size and API endpoint
  • Dark and light theme support
  • Event-based API for interaction with your application
  • Built with SolidJS for optimal performance
  • Accessibility is ensured with ARIA attributes, high-contrast mode support, and clear keyboard focus states

Supported tags (by our inject scripts)

  • textarea
  • input[type="text"]
  • input[type="search"]
  • input (without a type; defaults to text)
  • [contenteditable] elements

Usage

Auto-inject modes

Choose the auto-inject mode that best suits your needs:

| Mode | Description | Scripts | |---|---|---| | Exclusive | Enables for text fields with the data-dictate-button-on attribute only. | inject-exclusive.js | | Inclusive | Enables for text fields without the data-dictate-button-off attribute. | inject-inclusive.js |

Both auto-inject modes:

  • Automatically run on DOMContentLoaded (or immediately if the DOM is already loaded).
  • Watch for DOM changes to apply the dictate button to newly added elements.
  • Set the button’s language from document.documentElement.lang (if present). Long codes like en-GB are normalized to en.
  • Position the button to the top right-hand corner of the text field, respecting its padding with 4px fallback if the padding is not set (0).

From CDN

Option 1: Using the exclusive auto-inject script

In your HTML <head> tag, add the following script tag:

<script type="module" crossorigin src="https://cdn.dictate-button.io/inject-exclusive.js"></script>

Add the data-dictate-button-on attribute to any textarea, input[type="text"], input[type="search"], input without a type attribute, or element with the contenteditable attribute:

<textarea data-dictate-button-on></textarea>
<input type="text" data-dictate-button-on />
<input type="search" data-dictate-button-on />
<input data-dictate-button-on />
<div contenteditable data-dictate-button-on />

Option 2: Using the inclusive auto-inject script

In your HTML <head> tag, add the following script tag:

<script type="module" crossorigin src="https://cdn.dictate-button.io/inject-inclusive.js"></script>

All textarea, input[type="text"], input[type="search"], input elements without a type attribute, and elements with the contenteditable attribute that lack data-dictate-button-off will be automatically enhanced by default.

To disable that for a specific field, add the data-dictate-button-off attribute to it this way:

<textarea data-dictate-button-off></textarea>
<input type="text" data-dictate-button-off />
<input type="search" data-dictate-button-off />
<input data-dictate-button-off />
<div contenteditable data-dictate-button-off />

Option 3: Manual integration

Import the component and use it directly in your code:

<script type="module" crossorigin src="https://cdn.dictate-button.io/dictate-button.js"></script>

<dictate-button size="30" api-endpoint="https://api.dictate-button.io/transcribe" language="en"></dictate-button>

From NPM

Import once for your app:

// For selected text fields (with data-dictate-button-on attribute):
import 'dictate-button/inject-exclusive'
// or for all text fields (except those with data-dictate-button-off attribute):
import 'dictate-button/inject-inclusive'

To choose between exclusive and inclusive auto-inject modes, see the Auto-inject modes section.

Advanced usage with library functions

If you need more control over when and how the dictate buttons are injected, you can use the library functions directly:

Tip: You can also import from subpaths (e.g., 'dictate-button/libs/injectDictateButton') for smaller bundles, if your bundler resolves package subpath exports.

import 'dictate-button' // Required when using library functions directly
import { injectDictateButton, injectDictateButtonOnLoad } from 'dictate-button/libs'

// Inject dictate buttons immediately to matching elements
injectDictateButton(
  'textarea.custom-selector', // CSS selector for target elements
  {
    buttonSize: 30,           // Button size in pixels (optional; default: 30)
    verbose: false,           // Log events to console (optional; default: false)
    customApiEndpoint: 'https://api.example.com/transcribe' // Optional custom API endpoint
  }
)

// Inject on DOM load with mutation observer to catch dynamically added elements
injectDictateButtonOnLoad(
  'input.custom-selector',    // CSS selector for target elements
  {
    buttonSize: 30,           // Button size in pixels (optional; default: 30)
    verbose: false,           // Log events to console (optional; default: false)
    customApiEndpoint: 'https://api.example.com/transcribe', // Optional custom API endpoint
    watchDomChanges: true     // Watch for DOM changes (optional; default: false)
  }
)

Note: the injector mirrors the target field’s display/margins into the wrapper, sets wrapper width to 100% for block-level fields, and adds padding to avoid the button overlapping text. The wrapper also has the dictate-button-wrapper class for easy styling.

Events

The dictate-button component emits the following events:

  • recording:started: Fired when user starts recording.
  • recording:stopped: Fired when user stops recording.
  • recording:failed: Fired when an error occurs during recording.
  • transcribing:started: Fired when transcribing is started.
  • transcribing:finished: Fired when transcribing is complete. The event detail contains the transcribed text.
  • transcribing:failed: Fired when an error occurs during transcribing.

The ideal scenario is when user first starts recording (recording:started), then stops recording (recording:stopped), then the recorded audio is sent to the server for processing (transcribing:started), and finally the transcribed text is received (transcribing:finished).

recording:started -> recording:stopped -> transcribing:started -> transcribing:finished

In case of an error in recording or transcribing, the recording:failed or transcribing:failed event is fired, respectively.

Example event handling:

const dictateButton = document.querySelector('dictate-button');

dictateButton.addEventListener('transcribing:finished', (event) => {
  const transcribedText = event.detail;
  console.log('Transcribed text:', transcribedText);
  
  // Add the text to your input field
  document.querySelector('#my-input').value += transcribedText;
});

Attributes

| Attribute | Type | Default | Description | |---------------|---------|-----------------------------------------|----------------------------------------| | size | number | 30 | Size of the button in pixels | | apiEndpoint | string | https://api.dictate-button.io/transcribe| API endpoint for transcription service | | language | string | (not set) | Optional language code (e.g., 'en', 'fr', 'de') which may speed up the transcription. | | theme | string | (inherits from page) | 'light' or 'dark' | | class | string | | Custom CSS class |

Styling

You can customize the appearance of the dictate button using CSS parts:

/* Style the button container */
dictate-button::part(container) {
  /* Custom styles */
}

/* Style the button itself */
dictate-button::part(button) {
  /* Custom styles */
}

/* Style the button icons */
dictate-button::part(icon) {
  /* Custom styles */
}

API Endpoint

By default, dictate-button uses the https://api.dictate-button.io/transcribe endpoint for speech-to-text conversion. You can specify your own endpoint by setting the apiEndpoint attribute.

The API expects:

  • POST request
  • Multipart form data with the following fields:
    • audio: Audio data as a File (audio/webm format)
    • origin: The origin of the website (automatically added)
    • language: Optional language code (if provided as an attribute)
  • Response should be JSON with a text property containing the transcribed text

Browser Compatibility

The dictate-button component requires the following browser features:

  • Web Components
  • MediaRecorder API
  • Fetch API

Works in all modern browsers (Chrome, Firefox, Safari, Edge).