Skip to content

Focus Management

Focus management in dill-pixel provides keyboard navigation and visual feedback for interactive elements in your application. The system consists of multiple layers of focusable elements that can be navigated using the Tab key.

Focus layers provide a way to manage multiple sets of focusable elements in your application. Think of them as stackable groups of interactive elements where only one layer can be active at a time.

// Create a new focus layer
app.focus.addFocusLayer('menu');
app.focus.addFocusLayer('popup', false); // second param: don't make active
// Switch active layer
app.focus.setFocusLayer('popup');
// Remove a layer
app.focus.removeFocusLayer('menu');
  1. Menu Navigation: Separate menu items into their own layer
  2. Popups: Create a dedicated layer for popup content
  3. Game UI: Switch between different UI states (inventory, skills, etc.)

You can control the order of layers to manage focus priority:

// Set explicit layer order
app.focus.setLayerOrder(['popup', 'menu', 'game']);
app.focus.onFocusLayerChange.connect((layerId) => {
console.log(`Active layer changed to: ${layerId}`);
});

Each layer can have a default focusable element that receives focus when the layer becomes active:

// Set default focus when adding focusables
app.focus.addFocusable(menuButton, 'menu', true); // true = set as default
// Or when adding multiple elements
app.focus.addFocusLayer('menu', true, [
menuButton, // First element becomes default
optionsButton,
exitButton,
]);

Focus layers are automatically cleaned up when changing scenes, but you can also manually remove them:

// Remove specific layer
app.focus.removeFocusLayer('popup');
// Remove all layers
app.focus.removeAllFocusLayers();

Any container implementing the IFocusable interface can receive focus. The framework provides built-in focus support for components like Button.

// Add focusable elements to a layer
app.focus.addFocusable(button, 'main', true); // true = set as default focus
app.focus.addFocusable([element1, element2], 'popup');

The FocusOutliner provides visual feedback when elements receive focus. By default, it draws a cyan rectangle or rounded rectangle around the focused element.

Configure the default outliner’s appearance in your dill-pixel config:

OptionTypeDefaultDescription
colornumber0x00ffffOutline color in hex format
shape'rectangle' | 'rounded rectangle''rounded rectangle'Outline shape style
lineWidthnumber2Width of the outline in pixels
radiusnumber8Corner radius for rounded rectangle shape
dill-pixel.config.ts
export const config = defineConfig({
focus: {
outliner: {
color: 0x00ffff, // Cyan color (default)
shape: 'rounded rectangle', // 'rectangle' or 'rounded rectangle'
lineWidth: 2, // Outline thickness
radius: 8, // Corner radius (for rounded rectangle)
},
},
});

You can create your own focus outliner by extending the base FocusOutliner class:

  1. src/components/MyCustomOutliner.ts
    import { FocusOutliner } from 'dill-pixel';
    export class MyCustomOutliner extends FocusOutliner {
    public draw(focusTarget: IFocusable): void {
    this.clear();
    this.setFocusTarget(focusTarget);
    // Custom drawing logic here
    this._graphics.lineStyle(2, 0xff0000); // Red outline
    this._graphics.drawRect(0, 0, this.focusBounds.width, this.focusBounds.height);
    }
    }
  2. Configure the outliner in your dill-pixel.config.ts

    Section titled “Configure the outliner in your dill-pixel.config.ts”
    dill-pixel.config.ts
    import { defineConfig } from 'dill-pixel';
    import { MyCustomOutliner } from '@/components/MyCustomOutliner';
    export const config = defineConfig({
    //... rest ofyour config
    focus: {
    outliner: MyCustomOutliner, // Use custom outliner
    },
    });