Skip to main content
The glide.modes API allows you to register custom modes beyond the built-in ones.

Built-in Modes

Glide comes with the following built-in modes:
  • normal - Default navigation mode
  • insert - Text editing mode
  • visual - Visual selection mode
  • ignore - Pass through all keys to the page
  • command - Command-line mode
  • op-pending - Operator-pending mode (e.g., after pressing d)

Methods

register()

Register a custom mode with a specific caret style.
glide.modes.register<Mode extends keyof GlideModes>(
  mode: Mode,
  opts: { caret: "block" | "line" | "underline" }
): void

Parameters

mode
string
required
The name of the mode to register. Must be declared in the GlideModes interface first.
opts.caret
'block' | 'line' | 'underline'
required
The caret style to use in this mode:
  • block - Solid block cursor (like Vim normal mode)
  • line - Vertical line cursor (like Vim insert mode)
  • underline - Underline cursor

Example

To register a custom mode, you must first declare it in the type system:
// 1. Declare the mode type
declare global {
  interface GlideModes {
    leap: "leap";
  }
}

// 2. Register the mode at runtime
glide.modes.register('leap', { caret: 'block' });

// 3. Use it like any other mode
glide.keymaps.set('leap', 's', 'hint', {
  description: 'Show hints in leap mode'
});

glide.keymaps.set('normal', '<leader>l', 'mode_change leap', {
  description: 'Enter leap mode'
});
Implementation:
modes: {
  register(mode, opts) {
    if (GlideBrowser._modes[mode]) {
      throw new Error(`The \`${mode}\` mode has already been registered. Modes can only be registered once`);
    }

    GlideBrowser._modes[mode] = { caret: opts.caret };
    MODE_SCHEMA_TYPE.enum.push(mode);
    GlideBrowser.key_manager.register_mode(mode);
  },
}

list()

Returns an array of all registered mode names.
glide.modes.list(): GlideMode[]

Returns

An array of mode names (strings).

Example

const modes = glide.modes.list();
console.log('Available modes:', modes);
// Output: ["normal", "insert", "visual", "ignore", "command", "op-pending"]

// Check if a custom mode exists
if (modes.includes('leap')) {
  console.log('Leap mode is registered');
}
Implementation:
list() {
  return Object.keys(GlideBrowser._modes) as GlideMode[];
},

Type Declaration

The GlideModes interface defines all available modes:
interface GlideModes {
  normal: "normal";
  insert: "insert";
  visual: "visual";
  ignore: "ignore";
  command: "command";
  "op-pending": "op-pending";
}
The GlideMode type is derived from the interface keys:
type GlideMode = keyof GlideModes;

Complete Custom Mode Example

Here’s a complete example of creating a “search” mode for quick web searches:
// 1. Declare the mode type
declare global {
  interface GlideModes {
    search: "search";
  }
}

// 2. Register the mode
glide.modes.register('search', { caret: 'line' });

// 3. Create mappings for the mode
glide.keymaps.set('search', 'g', 'open https://google.com/search?q=', {
  description: 'Google search'
});

glide.keymaps.set('search', 'd', 'open https://duckduckgo.com/?q=', {
  description: 'DuckDuckGo search'
});

glide.keymaps.set('search', 'y', 'open https://youtube.com/results?search_query=', {
  description: 'YouTube search'
});

glide.keymaps.set('search', '<Esc>', 'mode_change normal', {
  description: 'Exit search mode'
});

// 4. Create an entry point from normal mode
glide.keymaps.set('normal', '<leader>s', 'mode_change search', {
  description: 'Enter search mode'
});

// 5. Add visual feedback with autocmd
glide.autocmds.create('ModeChanged', '*:search', () => {
  console.log('Entered search mode - press g/d/y for searches');
});

glide.autocmds.create('ModeChanged', 'search:*', () => {
  console.log('Exited search mode');
});

Mode-Specific Behavior

Checking Current Mode

if (glide.ctx.mode === 'normal') {
  console.log('Currently in normal mode');
}

const modes = glide.modes.list();
if (modes.includes(glide.ctx.mode)) {
  console.log('Valid mode:', glide.ctx.mode);
}

Mode Change Autocmds

// Trigger on entering any custom mode
glide.autocmds.create('ModeChanged', '*:search', ({ new_mode }) => {
  console.log('Entered search mode');
});

// Trigger on leaving custom mode
glide.autocmds.create('ModeChanged', 'search:*', ({ old_mode, new_mode }) => {
  console.log(`Left ${old_mode} mode, entered ${new_mode} mode`);
});

// Trigger on any mode change
glide.autocmds.create('ModeChanged', '*', ({ old_mode, new_mode }) => {
  console.log(`Mode changed: ${old_mode} -> ${new_mode}`);
});

Advanced Example: Modal Layer

Create a “window” mode for window management:
declare global {
  interface GlideModes {
    window: "window";
  }
}

glide.modes.register('window', { caret: 'block' });

// Window management mappings
const windowMappings = {
  'n': { cmd: 'window_new', desc: 'New window' },
  'c': { cmd: 'window_close', desc: 'Close window' },
  's': { cmd: 'window_switch', desc: 'Switch window' },
  'f': { cmd: 'window_fullscreen', desc: 'Toggle fullscreen' },
  'm': { cmd: 'window_minimize', desc: 'Minimize window' },
};

for (const [key, { cmd, desc }] of Object.entries(windowMappings)) {
  glide.keymaps.set('window', key, cmd, { description: desc });
}

// Exit back to normal
glide.keymaps.set('window', '<Esc>', 'mode_change normal');
glide.keymaps.set('window', 'q', 'mode_change normal');

// Enter window mode from normal
glide.keymaps.set('normal', '<leader>w', 'mode_change window', {
  description: 'Window mode'
});

// Show available commands when entering
glide.autocmds.create('ModeChanged', '*:window', () => {
  const modes = Object.entries(windowMappings)
    .map(([k, { desc }]) => `${k}: ${desc}`)
    .join(', ');
  console.log('Window mode:', modes);
});

Build docs developers (and LLMs) love