Skip to content

Browser Typing Tool

For Browser environment Lipi Lekhika includes a premade plugin for low-latency realtime typing. Only supported for textarea and input elements.

  1. Import the relevant functions from the package

    import {
    createTypingContext,
    clearTypingContextOnKeyDown,
    handleTypingBeforeInputEvent
    } from 'lipilekhika/typing';
  2. Create a typing context with the desired typing script and custom options. Create a new context for each typing script and element combination.

    const ctx = createTypingContext('Telugu');
  3. Call handleTypingBeforeInputEvent and pass the onbeforeinput event and the typing_context. The callback is optional and will be called with the updated value of the input element.

    handleTypingBeforeInputEvent(ctx, event, callback, options?);
  4. Add UI and I/O-Related Context Cleanup events. onblur handles focus of the input element and onkeydown handles keydown events (e.g. Arrow Keys, Esc, Etc).

    ctx.clearContext(); // onblur
    // onkeydown
    clearTypingContextOnKeyDown(event, ctx);

After creating a typing context, you can dynamically update typing options:

  • ctx.updateUseNativeNumerals(boolean) - Enable/disable native numerals (e.g., १० instead of 10)
  • ctx.updateIncludeInherentVowel(boolean) - Enable/disable inherent vowel inclusion (schwa deletion)
  • ctx.getUseNativeNumerals() - Get current native numerals setting
  • ctx.getIncludeInherentVowel() - Get current inherent vowel setting
  • ctx.getNormalizedScript() - Get current normalized script name

You can view all examples in live environment here

const ctx = useMemo(() => createTypingContext(script), [script]);
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
onBeforeInput={(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => setText(newValue))}
onBlur={() => ctx.clearContext()}
onKeyDown={(e) => clearTypingContextOnKeyDown(e, ctx)}
/>
const ctx = computed(() => createTypingContext(script.value));
<input
v-model="text"
@beforeinput="(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => (text = newValue))"
@blur="() => ctx.clearContext()"
@keydown="(e) => clearTypingContextOnKeyDown(e, ctx)"
></input>

In Vue you can eagerly await using

watchEffect(() => {
ctx.value.ready;
});
const ctx = $derived(createTypingContext(script));
<textarea
bind:value={text}
onbeforeinput={(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => (text = newValue))}
onblur={() => ctx.clearContext()}
onkeydown={(e) => clearTypingContextOnKeyDown(e, ctx)}
></textarea>

In Svelte you can eagerly await using

$effect(() => {
ctx.ready;
});
const ctx = createMemo(() => createTypingContext(script()));
<textarea
value={text()}
onInput={(e) => setText(e.currentTarget.value)}
onBeforeInput={(e) => handleTypingBeforeInputEvent(ctx(), e, (newValue) => setText(newValue))}
onBlur={() => ctx().clearContext()}
onKeyDown={(e) => clearTypingContextOnKeyDown(e, ctx())}
></textarea>

In Solid you can eagerly await using

createEffect(() => {
ctx().ready;
});

In Vanilla JS approach you will have to bind the events manually yourself.

Transliteration and even Rich text typing is usually built around real <textarea> and <input> elements. Wiring it directly to contenteditable is usually impractical: the DOM is not one simple string, and selection, IME, and paste are harder to keep consistent.

Rich editors typically use a mirror (or underlay) instead: a read-only layer shows colors, styling and other rich elements. All typing—including handleTypingBeforeInputEvent—targets that textarea.

So if the Rich Text editing library you are using provides a interface to underlyiing textarea element then you should be able to integrate Lipi Lekhika typing. For example in crata-md svelte library a textarea element is exposed for use.

<MarkdownEditor
{carta}
bind:value={content}
mode="tabs"
scroll="async"
placeholder="Write markdown…"
selectedTab="write"
textarea={{
onbeforeinput: (e: Event) =>
handleTypingBeforeInputEvent(ctx, e, (v) => (content = v), typing_enabled),
onblur: () => ctx.clearContext(),
onkeydown: (e: KeyboardEvent) => clearTypingContextOnKeyDown(e, ctx)
}}
/>
  • It demonstartes a mininal example of a shadow textarea element to enable rich text typing
  • Demo Link
  • Source Code