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

@dwack1234/arabic-keyboard-nextjs

v1.0.7

Published

A full-featured Arabic keyboard component for Next.js and React applications

Readme

Arabic Keyboard for Next.js

A fully-featured, customizable Arabic virtual keyboard web application built with Next.js 16, React 19, and TypeScript. Features an interactive virtual keyboard for typing Arabic text with support for tashkeel (diacritical marks), Alif variants, and real-time word display.

Version: 2.0.0
Last Updated: October 27, 2025


📑 Table of Contents


✨ Features

Core Functionality

  • Dual Language Support - Arabic (KBDA1) and English (QWERTY) layouts
  • Real-time Character Input - Character-by-character callback API
  • Comprehensive Callback System - 15+ event callbacks for complete control
  • Standalone or Integrated - Works as pure input device or with text areas
  • Modifier Keys - Shift, Ctrl, Alt support
  • Special Characters - Full Tashkeel (diacritics) support
  • Sound Effects - Keypress, clear, and UI sounds (optional)
  • Responsive Design - Works on all screen sizes
  • Floating Words Display - Completed words float across the screen with random positions and colors

Advanced Features

  • 🎨 Extensive Customization - 100+ settings across 11 categories
  • 🎵 Sound System - Multiple sound profiles with volume control
  • 📱 Touch Optimized - Smooth touch interactions
  • Accessibility - ARIA labels and keyboard navigation
  • 🌈 Theme Support - Multiple built-in themes
  • Performance - Optimized rendering with React 19
  • 📦 TypeScript - Full type safety with comprehensive interfaces
  • 🧪 Tested - Unit tests with Jest and React Testing Library

🚀 Getting Started

Prerequisites

  • Node.js 18+
  • npm, yarn, or pnpm

Installation

# Clone the repository
git clone https://github.com/d-wack/arabic-keyboard-nextjs.git
cd arabic-keyboard-nextjs

# Install dependencies
npm install

# Start development server
npm run dev

Open http://localhost:3000 to see the application.


🛠️ Development Commands

Running the Application

npm run dev          # Start development server (http://localhost:3000)
npm run build        # Build for production
npm start            # Start production server

Testing

npm test             # Run all tests with Jest
npm run test:watch   # Run tests in watch mode
npm run test:coverage # Run tests with coverage report

Linting

npm run lint         # Run ESLint

🏛️ Architecture

The application follows a clean component-based architecture:

Main Components

  1. src/app/page.tsx - Main page with demo selector and three demo modes:

    • Original: Floating words demo
    • Real-Time: Character-by-character display with statistics
    • Form: Multi-field form integration example
  2. src/components/ArabicKeyboard.tsx - Virtual keyboard component

    • Supports Arabic (KBDA1) and English (QWERTY) layouts
    • Three input modes: Normal, Shift (tashkeel), Ctrl (Alif variants)
    • Comprehensive callback API for integration
    • Physical keyboard support with visual feedback
  3. src/components/WordDisplay.tsx - Floating word display

    • Shows completed words as floating elements
    • Random positions, sizes, colors, and opacity
    • Click to remove words
  4. src/context/SettingsContext.tsx - Settings management

    • Centralized settings with localStorage persistence
    • 11 categories: appearance, layout, behavior, sound, animations, etc.

Key Features

  • Callback-based API: Character input, backspace, enter, clear, modifiers
  • Dual Modes: Standalone (internal state) or Integrated (external state via callbacks)
  • Settings System: 100+ customizable settings with live preview
  • Language Toggle: Alt+L keyboard shortcut or UI button

📚 Component API

ArabicKeyboard Props

interface ArabicKeyboardProps {
  // ===== REQUIRED =====
  isVisible: boolean;                    // Control keyboard visibility
  onToggle: () => void;                  // Toggle handler

  // ===== CALLBACK API =====
  callbacks?: KeyboardCallbacks;         // Event callbacks (see below)
  mode?: 'standalone' | 'integrated';    // Default: 'standalone'

  // ===== TARGET ELEMENT (Optional) =====
  targetInputRef?: React.RefObject<HTMLInputElement | HTMLTextAreaElement>;
  targetInputId?: string;
  autoFocusTarget?: boolean;             // Default: false
  syncWithTarget?: boolean;              // Default: true

  // ===== CONTROLLED MODE (Optional) =====
  value?: string;                        // External text value
  onValueChange?: (value: string) => void;
  cursorPosition?: number;
  onCursorPositionChange?: (position: number) => void;

  // ===== BEHAVIOR =====
  insertMode?: 'append' | 'cursor';      // Default: 'cursor'
  textChangeDebounce?: number;           // Default: 0 (ms)
  emitEventsInStandaloneMode?: boolean;  // Default: false

  // ===== LEGACY =====
  onWordComplete?: (word: string) => void; // Backward compatible
}

Callback API

The callback API provides 15+ events for complete control over keyboard interactions:

interface KeyboardCallbacks {
  // ===== CHARACTER INPUT =====
  onCharacterInput?: (
    char: string,
    metadata: InputMetadata
  ) => void;

  onBackspace?: (
    deletedText: string,
    metadata: Omit<InputMetadata, 'keyType'>
  ) => void;

  onTextChange?: (
    newText: string,
    previousText: string,
    changeType: 'insert' | 'delete' | 'clear' | 'external',
    metadata: InputMetadata
  ) => void;

  // ===== WORD & SUBMISSION =====
  onWordComplete?: (word: string) => void;
  
  onEnter?: (
    currentText: string,
    metadata: Omit<InputMetadata, 'keyType'>
  ) => void;

  onClear?: (
    clearedText: string,
    metadata: Omit<InputMetadata, 'keyType'>
  ) => void;

  // ===== MODIFIER KEYS =====
  onShiftToggle?: (isPressed: boolean) => void;
  onCtrlToggle?: (isPressed: boolean) => void;
  onAltToggle?: (isPressed: boolean) => void;

  // ===== CURSOR CONTROL =====
  onCursorMove?: (
    newPosition: number,
    oldPosition: number
  ) => void;

  onTextSelect?: (
    selectedText: string,
    startPos: number,
    endPos: number
  ) => void;

  // ===== KEYBOARD STATE =====
  onKeyboardOpen?: () => void;
  onKeyboardClose?: () => void;

  onLanguageChange?: (
    newLanguage: 'ar' | 'en',
    previousLanguage: 'ar' | 'en'
  ) => void;

  // ===== SPECIAL KEYS =====
  onSpacePressed?: () => void;
  onTabPressed?: () => void;
}

InputMetadata

Every callback includes metadata about the input context:

interface InputMetadata {
  keyType: 'letter' | 'number' | 'tashkeel' | 'special' | 'modifier';
  language: 'ar' | 'en';
  timestamp: number;
  cursorPosition: number;
  textLength: number;
  isShiftPressed: boolean;
  isCtrlPressed: boolean;
  isAltPressed: boolean;
  insertMode: 'append' | 'cursor';
}

💡 Usage Examples

See the live examples in the application:

  • Original Demo: Floating words display (default view)
  • Real-Time Demo: Character tracking with statistics
  • Form Demo: Multi-field form integration

Basic Integration

Example 1: Real-Time Display

'use client';

import { useState, useMemo } from 'react';
import ArabicKeyboard from '@/components/ArabicKeyboard';
import type { KeyboardCallbacks } from '@/types/keyboard.types';

export default function RealTimeExample() {
  const [displayText, setDisplayText] = useState('');
  const [eventLog, setEventLog] = useState<string[]>([]);
  const [stats, setStats] = useState({
    totalKeystrokes: 0,
    letters: 0,
    numbers: 0,
    tashkeel: 0,
  });

  const callbacks: KeyboardCallbacks = useMemo(() => ({
    onCharacterInput: (char, metadata) => {
      setDisplayText(prev => prev + char);
      setStats(prev => ({
        ...prev,
        totalKeystrokes: prev.totalKeystrokes + 1,
        letters: metadata.keyType === 'letter' ? prev.letters + 1 : prev.letters,
        numbers: metadata.keyType === 'number' ? prev.numbers + 1 : prev.numbers,
        tashkeel: metadata.keyType === 'tashkeel' ? prev.tashkeel + 1 : prev.tashkeel,
      }));
    },

    onBackspace: (deletedText) => {
      setDisplayText(prev => prev.slice(0, -deletedText.length));
    },

    onEnter: () => {
      setDisplayText(prev => prev + '\n');
    },

    onClear: () => {
      setDisplayText('');
    },

    onWordComplete: (word) => {
      setEventLog(prev => [...prev, `Word: ${word}`]);
    },
  }), []);

  return (
    <div>
      <div className="display" dir="rtl">
        {displayText || 'Start typing...'}
      </div>
      
      <div className="stats">
        <p>Keystrokes: {stats.totalKeystrokes}</p>
        <p>Letters: {stats.letters}</p>
        <p>Numbers: {stats.numbers}</p>
        <p>Tashkeel: {stats.tashkeel}</p>
      </div>

      <ArabicKeyboard
        isVisible={true}
        onToggle={() => {}}
        callbacks={callbacks}
        mode="integrated"
      />
    </div>
  );
}

Example 2: Form Integration

'use client';

import { useState, useMemo } from 'react';
import ArabicKeyboard from '@/components/ArabicKeyboard';
import type { KeyboardCallbacks } from '@/types/keyboard.types';

export default function FormExample() {
  const [currentField, setCurrentField] = useState<'name' | 'email' | 'bio' | null>(null);
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    bio: '',
  });

  const callbacks: KeyboardCallbacks = useMemo(() => ({
    onCharacterInput: (char) => {
      if (!currentField) return;
      setFormData(prev => ({
        ...prev,
        [currentField]: prev[currentField] + char,
      }));
    },

    onBackspace: () => {
      if (!currentField) return;
      setFormData(prev => ({
        ...prev,
        [currentField]: prev[currentField].slice(0, -1),
      }));
    },

    onEnter: () => {
      // Auto-advance to next field
      if (currentField === 'name') setCurrentField('email');
      else if (currentField === 'email') setCurrentField('bio');
    },

    onKeyboardClose: () => {
      setCurrentField(null);
    },
  }), [currentField]);

  return (
    <form>
      <input
        type="text"
        value={formData.name}
        onFocus={() => setCurrentField('name')}
        placeholder="Name"
      />
      
      <input
        type="text"
        value={formData.email}
        onFocus={() => setCurrentField('email')}
        placeholder="Email"
      />
      
      <textarea
        value={formData.bio}
        onFocus={() => setCurrentField('bio')}
        placeholder="Bio"
      />

      <ArabicKeyboard
        isVisible={currentField !== null}
        onToggle={() => setCurrentField(null)}
        callbacks={callbacks}
        mode="integrated"
      />
    </form>
  );
}

Example 3: Controlled Mode

'use client';

import { useState } from 'react';
import ArabicKeyboard from '@/components/ArabicKeyboard';

export default function ControlledExample() {
  const [text, setText] = useState('');
  const [cursor, setCursor] = useState(0);

  return (
    <>
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        onSelect={(e) => setCursor(e.currentTarget.selectionStart)}
      />

      <ArabicKeyboard
        isVisible={true}
        onToggle={() => {}}
        value={text}
        onValueChange={setText}
        cursorPosition={cursor}
        onCursorPositionChange={setCursor}
        mode="integrated"
      />
    </>
  );
}

⌨️ Keyboard Layouts

Arabic Layout (KBDA1)

Standard Arabic keyboard layout with full Tashkeel support:

Row 1: 1 2 3 4 5 6 7 8 9 0 - = Backspace
Row 2: Tab ض ص ث ق ف غ ع ه خ ح ج د \
Row 3: Shift ش س ي ب ل ا ت ن م ك ط Enter
Row 4: Ctrl ئ ء ؤ ر لا ى ة و ز ظ / Shift
Row 5: Alt Space Alt

Tashkeel (Diacritics):

  • Fatha (َ), Damma (ُ), Kasra (ِ)
  • Sukun (ْ), Shadda (ّ), Tanween variants
  • Hamza variants, Alef variants

English Layout (QWERTY)

Standard QWERTY layout with full punctuation:

Row 1: 1 2 3 4 5 6 7 8 9 0 - = Backspace
Row 2: Tab Q W E R T Y U I O P [ ] \
Row 3: Shift A S D F G H J K L ; ' Enter
Row 4: Ctrl Z X C V B N M , . / Shift
Row 5: Alt Space Alt


⚙️ Settings & Configuration

The keyboard includes comprehensive settings across 11 categories:

1. Appearance & Theme

appearance: {
  theme: 'dark' | 'light' | 'high-contrast' | 'minimal' | 'colorful' | 'custom',
  keyboardBackground: string,      // CSS color
  regularKeyColor: string,
  numberKeyColor: string,
  tashkeelKeyColor: string,
  specialKeyColors: {
    backspace: string,
    enter: string,
    space: string,
    clear: string,
    shift: string,
    ctrl: string,
    alt: string,
  },
}

2. Layout & Positioning

layout: {
  position: 'bottom-center' | 'bottom-left' | 'bottom-right' | 
            'top-center' | 'top-left' | 'top-right' | 'floating',
  width: 'full' | 'auto' | number,     // px or percentage
  height: 'auto' | number,              // px
  keySize: 'small' | 'medium' | 'large' | number,
  keySpacing: 'tight' | 'normal' | 'relaxed' | number,
  rowSpacing: 'tight' | 'normal' | 'relaxed' | number,
  borderRadius: number,                 // px
  padding: number,                      // px
}

3. Behavior

behavior: {
  autoCapitalize: boolean,
  doubleClickDelay: number,             // ms
  longPressDelay: number,               // ms
  repeatDelay: number,                  // ms for key repeat
  repeatInterval: number,               // ms
  closeOnClickOutside: boolean,
  closeOnEnter: boolean,
  closeOnEscape: boolean,
}

4. Sound Effects

sound: {
  enabled: boolean,
  volume: number,                       // 0-100
  keypress: {
    enabled: boolean,
    sound: 'click' | 'tap' | 'mechanical' | 'silent' | 'custom',
    volume: number,
  },
  clear: {
    enabled: boolean,
    sound: string,
    volume: number,
  },
  enter: {
    enabled: boolean,
    sound: string,
    volume: number,
  },
}

5. Animations

animations: {
  enabled: boolean,
  slideIn: boolean,
  slideOut: boolean,
  duration: number,                     // ms
  keyHoverEffect: 'none' | 'scale' | 'glow' | 'lift',
  keyPressEffect: 'none' | 'ripple' | 'scale' | 'glow',
}

6. Language Settings

language: {
  default: 'ar' | 'en',
  allowToggle: boolean,
  showLanguageIndicator: boolean,
  rtlDirection: boolean,
}

7. Special Keys

specialKeys: {
  showTashkeel: boolean,
  showNumbers: boolean,
  showEnglish: boolean,
  showEmoji: boolean,
  customKeys: Array<{
    label: string,
    value: string,
    position: number,
  }>,
}

8. Accessibility

accessibility: {
  ariaLabels: boolean,
  keyboardNavigation: boolean,
  highContrast: boolean,
  screenReaderAnnouncements: boolean,
  focusIndicator: boolean,
}

9. Performance

performance: {
  virtualScrolling: boolean,
  memoization: boolean,
  lazyLoadSounds: boolean,
  debounceDelay: number,                // ms
}

10. Display

display: {
  showTextArea: boolean,                // Deprecated in v2.0
  textAreaHeight: number,
  fontSize: number,
  fontFamily: string,
  showClearButton: boolean,
  showCloseButton: boolean,
}

11. Advanced

advanced: {
  enableLogging: boolean,
  debugMode: boolean,
  customCSS: string,
  allowMultipleInstances: boolean,
}

Using Settings

import { SettingsProvider, useSettings } from '@/context/SettingsContext';

function App() {
  return (
    <SettingsProvider initialSettings={{
      appearance: { theme: 'dark' },
      sound: { enabled: true, volume: 75 },
      layout: { position: 'bottom-center' },
    }}>
      <MyKeyboardComponent />
    </SettingsProvider>
  );
}

function MyKeyboardComponent() {
  const { settings, updateSettings } = useSettings();

  return (
    <ArabicKeyboard
      isVisible={true}
      onToggle={() => {}}
      // Settings are automatically applied via context
    />
  );
}

🔤 TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  ArabicKeyboardProps,
  KeyboardCallbacks,
  InputMetadata,
  KeyboardSettings,
  KeyType,
  Language,
} from '@/types/keyboard.types';

Key Types

type KeyType = 'letter' | 'number' | 'tashkeel' | 'special' | 'modifier';
type Language = 'ar' | 'en';
type InsertMode = 'append' | 'cursor';
type ChangeType = 'insert' | 'delete' | 'clear' | 'external';

🌐 Browser Support

  • ✅ Chrome 90+
  • ✅ Firefox 88+
  • ✅ Safari 14+
  • ✅ Edge 90+
  • ✅ Mobile browsers (iOS Safari, Chrome Mobile)

Requirements:

  • React 18+ (React 19 recommended)
  • Next.js 14+ (Next.js 15+ recommended)
  • Modern browser with ES6 support

🧪 Testing

The project includes comprehensive unit tests using Jest and React Testing Library.

Running Tests

npm test                 # Run all tests
npm test -- --watch      # Watch mode
npm test -- --coverage   # With coverage report

Test Structure

Tests are organized in src/components/__tests__/:

  • ArabicKeyboard.test.tsx - Keyboard component tests
  • WordDisplay.test.tsx - Floating words display tests
  • Settings.test.tsx - Settings context and modal tests

Test Coverage

  • Visibility and toggle behavior
  • Keyboard key rendering (Arabic/English layouts)
  • Callback integration (character input, backspace, etc.)
  • Modifier keys (Shift, Ctrl, Alt)
  • Settings persistence
  • Accessibility

🤝 Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Run tests to ensure everything works (npm test)
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Development Guidelines

  • Follow existing code style and patterns
  • Add tests for new features
  • Update documentation as needed
  • Ensure all tests pass before submitting PR
  • Run npm run lint to check for linting errors

📄 License

MIT License - see LICENSE file for details


🙏 Acknowledgments

  • Arabic keyboard layout based on KBDA1 standard
  • Sound effects from open source libraries
  • Built with Next.js, React, and TypeScript
  • Styled with Tailwind CSS

📞 Support


🗺️ Roadmap

v2.1 (Planned)

  • [ ] Swipe gesture support
  • [ ] Voice input integration
  • [ ] Predictive text
  • [ ] Custom layouts API

v3.0 (Future)

  • [ ] Multi-language support (French, Spanish, etc.)
  • [ ] Emoji picker integration
  • [ ] Advanced autocomplete
  • [ ] Cloud sync for settings

Made with ❤️ for the Arabic-speaking developer community