Whakerexa > Extras > KeyPiano

Description

KeyPiano is a generic clickable "piano" of buttons that composes a technical sequence -- made of codes and separators that are hard to type by hand -- into a target text field. Only the content of the keys (images, text, values) is domain-specific and stays in the HTML written by the consuming page; KeyPiano only knows about groups of keys, two separators, and the target field.

JavaScript

The KeyPiano class is activated on an existing container element. It reads its configuration from the container's data-* attributes and from its .wexa-key-piano-group children, found in document order.

Usage example:

<script type="module">
    import { KeyPiano } from '../wexa_statics/js/extras/keypiano/keypiano.js';

    const piano = new KeyPiano(document.getElementById('my-piano'));
</script>

HTML

The container carries the following data-* attributes:

Each .wexa-key-piano-group child is either:

<div class="wexa-key-piano" id="my-piano"
     data-target="my-target-field" data-group-sep="-" data-key-sep=".">

    <div class="wexa-key-piano-group" data-mode="radio" aria-label="Group 1">
        <label class="wexa-key-piano-key">
            <input type="radio" value="1">
            1
        </label>
        ...
    </div>

    <div class="wexa-key-piano-group" data-mode="radio" aria-label="Group 2">
        ...
    </div>

</div>

Radio and free groups can be mixed in a single container. Free groups always respond to clicks; radio groups only respond when it is their turn in the cycle.

KeyPiano itself injects, at the end of the container: a "delete last key" button, a "clear all" button (both using the shared Whakerexa mono-svg icons), and a visually-hidden aria-live="polite" status region announcing every action to screen reader users.

"Delete last key" has two behaviours depending on context:

Every change to the target field dispatches a real input event (with bubbles: true), so consuming pages can react to piano-driven changes the same way they react to keyboard input.

Real native <input type="radio"> and <button> elements are used throughout, so keyboard navigation and focus styling are already covered by Whakerexa's global rules -- nothing to add.

Retargeting

piano.setTarget(fieldId) points the piano at a different target field, discarding any in-progress entry and undo history. Useful when a single shared piano serves several fields in turn (e.g. opened from different rows of a table).

const piano = new KeyPiano(document.getElementById('my-piano'));

// later, when the context changes:
piano.setTarget('other-field-id');

Demo

Example 1: two "radio" groups (e.g. a two-part code)

Click a key in "Group A", then a key in "Group B": one entry is appended only once both groups have a choice. "Delete last key" undoes the last selection while a choice is in progress, or removes the last full entry otherwise.

Example 2: one "free" group (e.g. a phoneme sequence)

Every click appends its value immediately, separated by the outer separator.

Example 3: mixed "radio" + "free" groups

Radio groups take turns (Group A first, then Group B); the free group appends immediately at any time. The entry is composed and appended only once both radio groups have a selection.