Integration reference · v0.1.1 GitHub Playground Landing

Integration

Everything an integrator needs — and every example on this page is the real widget, running live next to its code.

npm install kurdish-keyboard

01 · Quick start

Attach, type, detach

One import per layout, one call. The panel renders after the field; clicking keys inserts at the caret (replacing any selection) and keeps the field's focus. kb.detach() removes the panel and undoes every side effect.

import { KurdishKeyboard } from 'kurdish-keyboard';
import 'kurdish-keyboard/styles.css'; // optional, recommended
import sorani from 'kurdish-keyboard/layouts/sorani';

const kb = KurdishKeyboard.attachTo(
  document.querySelector('input'),
  { layout: sorani },
);
// later: kb.detach()

Live

OptionTypeDefaultWhat it does
layoutLayoutminimal panelThe layout to render — import one per script, or pass your own.
suppressNativebooleanfalseSets inputmode="none" so mobile browsers keep the native keyboard hidden.
position'inline' | 'docked' | 'floating''inline'Panel placement — see Mobile below.
labelLanguage'en' | 'ku''en'Language of assistive-tech labels (Shift, Space, …).

02 · Layouts

Three layouts, live toggling

One entry point per layout — a Sorani-only site never bundles Kurmanji data (tree-shaking is proven in the release checks). setLayout() swaps live: the panel re-renders, direction flips RTL↔LTR, shift/caps state resets. Latin layouts add ⇪ Caps Lock automatically; Shift is one-shot everywhere.

import sorani from 'kurdish-keyboard/layouts/sorani';
import phonetic from 'kurdish-keyboard/layouts/kurmanji-phonetic';
import official from 'kurdish-keyboard/layouts/kurmanji-official';

kb.setLayout(phonetic); // live swap, LTR
kb.setLayout(sorani);   // back to RTL

Live

Custom layouts: a layout is plain data (the Layout type is exported; JSON validates against the published schema). Keys emit strings, not characters — CLDR's Shift+و is وو. The engine renders any conforming layout unchanged and never branches on a layout's name. The verified codepoint table ships as data at kurdish-keyboard/codepoints.json if you want to validate your own. RTL fields: the panel manages its own direction, but the field's dir belongs to your page — use dir="rtl" or dir="auto" for Sorani fields (the widget logs a console hint if you forget).

03 · Mobile

Be the keyboard

suppressNative applies inputmode="none" — the standard way to tell mobile browsers "this page provides its own keyboard". The trade-off is losing native autocorrect for that field, which is why it's per-field opt-in. docked fixes the panel to the viewport bottom and reserves body padding so the field is never hidden; floating hovers near the corner. Touch targets grow to 44px from a pointer: coarse capability query — never user-agent sniffing.

KurdishKeyboard.attachTo(field, {
  layout: sorani,
  suppressNative: true,
  position: 'docked',
});

Live — try docked on a phone

On desktop you'll see the fixed panel; on a phone inputmode="none" also keeps the system keyboard away.

04 · Theming

Custom properties, no CSS-in-JS

Import the stylesheet once, then set --kkb-* properties on the panel or any ancestor. The stylesheet is optional and static — the widget works unstyled. Both widgets below differ only in custom properties.

Default

Night — via --kkb-* only

.theme-night {
  --kkb-key-bg: #1e293b;
  --kkb-key-color: #e2e8f0;
  --kkb-key-border: #334155;
  --kkb-pressed-bg: #334155;
  --kkb-focus-color: #38bdf8;
  --kkb-surface-bg: #1e293b;
}
PropertyDefaultStyles
--kkb-gap4pxSpacing between keys and rows
--kkb-key-size2.2rem (44px coarse pointer)Key minimum width/height
--kkb-key-font-size1.1rem (1.3rem coarse pointer)Key label size
--kkb-key-bgButtonFaceKey background
--kkb-key-colorButtonTextKey label color
--kkb-key-border40% ButtonText mixKey border color
--kkb-key-radius4pxKey corner radius
--kkb-pressed-bg#cbdceeActive Shift/Caps background
--kkb-focus-color#1a56a0Keyboard-focus outline
--kkb-surface-bgCanvasDocked/floating panel background

Internal --_* properties are derived — override only the public ones.

05 · Accessibility

APG keyboard navigation, spoken names

The panel is a labelled role="group" of native buttons following the WAI-ARIA roving-tabindex pattern: one Tab stop, arrows move between keys (following visual direction — inverted in RTL panels), Home/End jump within a row, Enter/Space activate. Invisible keys get explicit labels (Space, ZWNJ, ⇧ Shift, ⇪ Caps Lock), focus survives re-renders, and :focus-visible shows a ≥3:1 outline.

// at attach time…
KurdishKeyboard.attachTo(field, {
  layout: sorani,
  labelLanguage: 'ku',
});

// …or live
kb.setLabelLanguage('en');

Live — what the ⇧ key announces

Shift announces as “”. Tab into the panel and drive it with arrow keys.

06 · Legacy text

normalizeLegacy()

Converts legacy fragmented Sorani (Arabic ك/ي, heh-for-ە) to the unified codepoints, driven by the same data file as the keyboard. DOM-free — it runs in Node, workers, and CLIs.

import { normalizeLegacy } from 'kurdish-keyboard/normalize';

normalizeLegacy('كوردي'); // → 'کوردی'
normalizeLegacy('ئێمه');  // → 'ئێمە'

Live — changed characters highlighted

Contract, read before piping text through it: the input is assumed to be Kurdish — ك→ک and ي→ی apply unconditionally, so genuine Arabic quotations convert too (segment non-Kurdish content yourself; there is no language detection). The heh→ە rule is a positional heuristic: word-final ه converts (including before ZWNJ), ه before another Arabic letter, tatweel, or a diacritic doesn't; medial legacy vowels are not caught and no dictionary is consulted. Latin text passes through untouched.

07 · CDN

No build step

The IIFE bundle exposes a global KurdishKeyboard whose attachTo accepts string layout names'sorani', 'kurmanji-phonetic', 'kurmanji-official' — or Layout objects (unknown names throw, listing the options). It also carries a layouts registry and normalizeLegacy. All layouts are bundled here — string convenience is the point; use the module entries when you have a bundler.

<script src="https://unpkg.com/kurdish-keyboard"></script>
<script>
  KurdishKeyboard.attachTo(document.querySelector('input'), {
    layout: 'sorani',
  });
</script>

08 · Frameworks

React, Vue, Svelte — no wrappers needed

Every insertion dispatches a bubbling input event (inputType: 'insertText') on the field, so framework bindings observe changes exactly as if the user had typed. Attach on mount, detach on unmount.

// React
function KurdishInput() {
  const [value, setValue] = useState('');
  const ref = useRef(null);
  useEffect(() => {
    const kb = KurdishKeyboard.attachTo(ref.current, { layout: sorani });
    return () => kb.detach();
  }, []);
  return <input dir="rtl" ref={ref} value={value}
           onChange={(e) => setValue(e.target.value)} />;
}
<!-- Vue -->
<script setup>
const text = ref('');
const field = ref(null);
let kb;
onMounted(() => { kb = KurdishKeyboard.attachTo(field.value, { layout: sorani }); });
onUnmounted(() => kb?.detach());
</script>
<template>
  <input dir="rtl" ref="field" v-model="text" />
</template>

<!-- Svelte: bind:value works the same way —
     the bubbling input event drives the binding -->

09 · Platform limits

What it cannot do, and why

Browser rules, not roadmap items.

Cannot type into cross-origin iframes
The same-origin policy denies all DOM access to embedded third-party pages.
Cannot simulate real keystrokes
Script-created keyboard events have isTrusted: false; browsers ignore their default actions. The widget therefore mutates the field value directly via setRangeText() — which works everywhere, including password fields.
suppressNative costs native autocorrect
inputmode="none" removes the whole native input surface for that field. Inherent to the mechanism — hence per-field opt-in.
Rich text / contenteditable
Not a browser limit — deliberately out of scope for v1; on the roadmap.
Browser support
Evergreen browsers from roughly the last three years, plus Safari 15.4+. One graceful degradation: the default key border uses color-mix() (Safari 16.2+) — older browsers simply render keys without it, or set --kkb-key-border yourself. No polyfills ship.

The markdown version of this reference lives in the repo: docs/integration-guide.md.