Glide’s hints system allows you to interact with clickable elements on a page using the keyboard. When activated, hints display labels over interactive elements that you can type to select them.
Basic Usage
The simplest way to use hints is with the default keybindings:
Activate hints
Press f in normal mode to show hints for all clickable elements on the page.
Type the hint label
Each element gets a unique label (like hj, as, df). Type the label to select that element.
Element is clicked
When you complete a hint label, the element is clicked and you return to normal mode.
Default Hint Keybindings
// Click element in current tab
glide . keymaps . set ( "normal" , "f" , "hint" );
// Click element in new tab
glide . keymaps . set ( "normal" , "F" , "hint --action=newtab-click" );
// Show hints for browser UI elements
glide . keymaps . set ( "normal" , "<leader>f" , "hint --location=browser-ui" );
// Cancel hints
glide . keymaps . set ( "hint" , "<Esc>" , "hints_remove" );
// Focus the largest input field
glide . keymaps . set ( "normal" , "gI" , () =>
glide . hints . show ({
auto_activate: true ,
editable: true ,
pick: hinting . pickers . biggest_area
})
);
// Yank (copy) a link URL
glide . keymaps . set ( "normal" , "yf" , () =>
glide . hints . show ({
selector: "[href]" ,
async action ({ content }) {
let href = await content . execute (( target ) =>
( target as HTMLAnchorElement ). href
);
if ( href . startsWith ( "mailto:" )) {
href = href . slice ( 7 );
} else if ( href . startsWith ( "tel:" ) || href . startsWith ( "sms:" )) {
href = href . slice ( 4 );
}
await navigator . clipboard . writeText ( href );
},
})
);
Programmatic API
Use glide.hints.show() to trigger hints with custom options:
Basic Example
// Show hints for all clickable elements
glide . hints . show ();
// Show hints only for links
glide . hints . show ({ selector: "a[href]" });
// Show hints for input fields
glide . hints . show ({ editable: true });
Selector Filtering
Use CSS selectors to target specific elements:
// Only show hints for buttons
glide . hints . show ({
selector: "button"
});
// Multiple selectors
glide . hints . show ({
selector: "button, input[type='submit'], .clickable"
});
// Include additional elements beyond defaults
glide . hints . show ({
include: ".custom-button, [role='button']"
});
selector replaces the default hintable elements, while include adds to them.
Hintable Elements
By default, Glide shows hints for these element types:
Custom Actions
Define what happens when a hint is selected:
// Custom action on hint selection
glide . hints . show ({
selector: "img" ,
async action ({ hint , content }) {
// Get image src from content
const src = await content . execute (( img ) =>
( img as HTMLImageElement ). src
);
console . log ( "Image URL:" , src );
console . log ( "Hint position:" , hint . x , hint . y );
},
});
// Copy link text instead of clicking
glide . hints . show ({
selector: "a" ,
async action ({ content }) {
const text = await content . execute (( link ) =>
link . textContent ?. trim () || ""
);
await navigator . clipboard . writeText ( text );
},
});
Action Context
The action callback receives:
hint - Hint metadata (position, id, dimensions)
content.execute() - Run code in page context with access to the DOM element
interface HintActionContext {
hint : {
id : number ;
x : number ;
y : number ;
width : number ;
height : number ;
};
content : {
execute < T >( callback : ( element : HTMLElement ) => T ) : Promise < T >;
};
}
Hint Labels
Customize how hint labels are generated:
Built-in Label Generators
Prefix-Free (Default)
Numeric
Generates labels where no label is a prefix of another, allowing instant selection: glide . o . hint_label_generator = glide . hints . label_generators . prefix_free ;
Uses characters from glide.o.hint_chars (default: "hjklasdfgyuiopqwertnmzxcvb"). Example labels : hj, hk, hl, as, ad, afSimple numeric labels starting from 1: glide . o . hint_label_generator = glide . hints . label_generators . numeric ;
Example labels : 1, 2, 3, 4, 5
Custom Label Generator
Create your own label generation logic:
glide . o . hint_label_generator = ({ hints }) => {
// Return an array of labels, one per hint
return hints . map (( hint , index ) => {
return String . fromCharCode ( 65 + index ); // A, B, C, ...
});
};
// Or use uppercase letters
glide . o . hint_label_generator = ({ hints }) => {
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
return hints . map (( _ , i ) => letters [ i ] || String ( i ));
};
Per-Hint Custom Labels
Generate labels based on hint properties:
glide . hints . show ({
selector: "a" ,
async label_generator ({ hints , content }) {
// Access DOM elements to generate labels
const texts = await content . map (( el ) =>
el . textContent ?. trim (). slice ( 0 , 2 ). toLowerCase () || ""
);
return texts . map (( text , i ) => text || String ( i ));
},
});
Hint Appearance
Customize hint styling:
// Change hint font size
glide . o . hint_size = "14px" ;
// Change hint characters (affects prefix-free generator)
glide . o . hint_chars = "asdfjkl;" ;
For advanced styling, use CSS:
glide . styles . add ( `
.glide-internal-hint-marker {
font-size: 16px !important;
font-weight: bold !important;
background: #ff6b35 !important;
color: white !important;
}
.glide-matching-character {
color: #ffcc00 !important;
}
` , { id: "custom-hints" });
Hint Pickers
Filter and select specific hints from the resolved set:
Biggest Area Picker
Select only the largest element (useful for focusing main input):
glide . hints . show ({
editable: true ,
pick: glide . hints . pickers . biggest_area ,
auto_activate: true ,
});
Source: src/glide/browser/base/content/hinting.mts:180-203
Custom Picker
Implement your own filtering logic:
glide . hints . show ({
async pick ({ hints , content }) {
// Only show hints in the top half of the viewport
return hints . filter ( hint => hint . y < window . innerHeight / 2 );
},
});
// Or pick based on DOM properties
glide . hints . show ({
selector: "a" ,
async pick ({ hints , content }) {
// Get href for each hint
const hrefs = await content . map (( el ) =>
( el as HTMLAnchorElement ). href
);
// Only keep external links
return hints . filter (( hint , i ) =>
! hrefs [ i ]. startsWith ( window . location . origin )
);
},
});
Auto-Activation
Automatically click when only one hint is found:
// Auto-activate if there's only one hint
glide . hints . show ({
editable: true ,
auto_activate: true
});
// Always auto-activate (even with multiple hints)
glide . hints . show ({
selector: "#submit-button" ,
auto_activate: "always"
});
Browser UI Hints
Show hints for browser interface elements:
// Show hints for browser UI (tabs, buttons, etc.)
glide . keymaps . set ( "normal" , "<leader>f" , "hint --location=browser-ui" );
// Programmatic
glide . hints . show ({ location: "browser-ui" });
Use browser UI hints to interact with tabs, address bar, bookmarks, and other Firefox interface elements.
Hint Mode
When hints are shown, Glide enters hint mode:
// Registered in plugins/hints.mts
glide . modes . register ( "hint" , { caret: "block" });
// Auto-cleanup when leaving hint mode
glide . autocmds . create ( "ModeChanged" , "hint:*" , async () => {
if ( ! glide . prefs . get ( "ui.popup.disable_autohide" )) {
await glide . excmds . execute ( "hints_remove" );
}
});
Advanced Examples
Copy All Links on Page
glide . keymaps . set ( "normal" , "<leader>yl" , async () => {
const links = await glide . content . execute (() => {
return Array . from ( document . querySelectorAll ( "a[href]" ))
. map ( a => ( a as HTMLAnchorElement ). href );
});
await navigator . clipboard . writeText ( links . join ( " \n " ));
console . log ( `Copied ${ links . length } links` );
});
Hint YouTube Timestamps
glide . autocmds . create ( "UrlEnter" , /youtube \. com/ , () => {
glide . keymaps . set ( "normal" , "<leader>t" , () => {
glide . hints . show ({
selector: "a.yt-simple-endpoint[href*='&t=']" ,
async action ({ content }) {
await content . execute (( el ) => {
( el as HTMLAnchorElement ). click ();
});
},
});
});
});
Focus Largest Textarea
glide . keymaps . set ( "normal" , "gI" , () =>
glide . hints . show ({
editable: true ,
auto_activate: true ,
pick : async ({ hints , content }) => {
const areas = await content . map (( el ) =>
el . offsetWidth * el . offsetHeight
);
let maxArea = 0 ;
let maxIndex = 0 ;
areas . forEach (( area , i ) => {
if ( area > maxArea ) {
maxArea = area ;
maxIndex = i ;
}
});
return [ hints [ maxIndex ]];
},
})
);
Source Code References
Hints API : src/glide/browser/base/content/glide.d.ts:620-680
Hint resolution : src/glide/browser/base/content/hinting.mts:24-204
Browser UI hints : src/glide/browser/base/content/browser-hints.mts:12-256
Hint mode registration : src/glide/browser/base/content/plugins/hints.mts:19
Default hint keymaps : src/glide/browser/base/content/plugins/keymaps.mts:40-147
Hintable element definitions : src/glide/browser/base/content/hinting.mts:101-128