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
| Option | Type | Default | What it does |
|---|---|---|---|
layout | Layout | minimal panel | The layout to render — import one per script, or pass your own. |
suppressNative | boolean | false | Sets 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;
}
| Property | Default | Styles |
|---|---|---|
--kkb-gap | 4px | Spacing between keys and rows |
--kkb-key-size | 2.2rem (44px coarse pointer) | Key minimum width/height |
--kkb-key-font-size | 1.1rem (1.3rem coarse pointer) | Key label size |
--kkb-key-bg | ButtonFace | Key background |
--kkb-key-color | ButtonText | Key label color |
--kkb-key-border | 40% ButtonText mix | Key border color |
--kkb-key-radius | 4px | Key corner radius |
--kkb-pressed-bg | #cbdcee | Active Shift/Caps background |
--kkb-focus-color | #1a56a0 | Keyboard-focus outline |
--kkb-surface-bg | Canvas | Docked/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 viasetRangeText()— 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-borderyourself. No polyfills ship.
The markdown version of this reference lives in the repo: docs/integration-guide.md.