Skip to main content

I put together a bunch of hotkeys to make my own life easier, and figured I might as well clean it up and post it in case any one else found them useful!

This all works via a Tampermonkey script, and installation instructions can be found below

Demo

Change Log

  • 7 Oct 2022
    • Updated to handle new field menu items
  • 24 Mar 2023
    • Updated to handle new field option layout
    • Firefox now uses MetaLeft; script updated to use it
  • 28 Mar 2023
    • Updated to handle new formula field HTML
  • 29 June 2024
    • Updated to handle new create button selector ID

Shortcut List

⌘/Left Alt + ⇧ Left Shift + 'Add a new field
⌘/Left Alt + ⇧ Right ShiftCustomize Field modal - Click “Save”
⌘/Left Alt + 'Next field header
⌘/Left Alt + ;Previous field header
sNext field menu option
wPrevious field menu option
⌘/Left Alt + ↵ Enter“Click” selected field menu option
⌘/Left Alt + ↵ EnterOpen field menu for selected field
EscapeDeselect
⌘/Left Alt + ⇧ Left Shift + 1Select first cell

Want another hotkey? Tell me about it and I’ll see what I can do!

How to use

  1. Install Tampermonkey
  2. Open the extension, click “Create a new script”, and paste the code found at the end of the post into it and save
  3. You’re done!

Notes

I’ve tested this mostly on Firefox on a Mac, but have also tested it a bit on:

  1. Chrome - Mac
  2. Firefox - Windows
  3. Chrome - Windows

And so it should be fine, but do let me know if you hit any issues and I’ll do my best to fix it

You can also customize the keys used as well, and instructions on how can be found in the code itself!

 

 

 

 

 

 

// ==UserScript==
// @name Airtable Hotkeys 1
// @description Adds custom hotkeys to Airtable
// @author Adam - The Time Saving Company
// @author adam@thetimesaving.company
// @match https://airtable.com/*
// @grant GM_addStyle

// ==/UserScript==
let osLeftKey

if(navigator.userAgent.includes("Windows")){
osLeftKey = "AltLeft"
}
else{
osLeftKey = "MetaLeft"
}

// CUSTOMIZATION START
// Changes made here will overwrite the default hotkeys and may cause some weirdness
// Feel free to make changes, but do check against the default hotkey list
// We can use this site to find out what the keys' name is: https://www.toptal.com/developers/keycode/for/enter
// Specifically, look for the value of the "event.code" section

// Set the two keys to press in conjunction that will then hit the "Save" button so that we don't have to use the mouse to click it anymore
// IMPORTANT THING TO NOTE: The key "Enter" cannot be used here as it's in use by Airtable
let saveKey1 = osLeftKey
let saveKey2 = "ShiftRight"

// Set the keys to press in conjunction that will then hit the "Add New Field" button
let addFieldKey1 = osLeftKey
let addFieldKey2 = "ShiftLeft"
let addFieldKey3 = "Quote"

// Set the keys to press in conjunction that will select the field header to the left
let fieldHeaderPrev1 = osLeftKey
let fieldHeaderPrev2 = "Semicolon"

// Set the keys to press in conjunction that will select the field header to the right
let fieldHeaderNext1 = osLeftKey
let fieldHeaderNext2 = "Quote"

// Set the keys to press in conjunction that will open the menu of the selected field header i.e. right clicking it
let fieldMenuOpenKey1 = osLeftKey
let fieldMenuOpenKey2 = "Enter"

// Set the keys to press to move up and down the field's menu
let fieldMenuNavigateUp = "KeyW"
let fieldMenuNavigateDown = "KeyS"

// Set the keys to press in conjunction that will click the selected menu item (i.e. "Customize type", "Rename" etc)
let fieldMenuOptionSelectKey1 = osLeftKey
let fieldMenuOptionSelectKey2 = "Enter"

// Set the key to press that will unselect everything
let escapeKey = "Escape"

let selectFirstCellKey1 = osLeftKey // CMD / Windows button
let selectFirstCellKey2 = "ShiftLeft"
let selectFirstCellKey3 = "Digit1"
// CUSTOMIZATION END

GM_addStyle('.column-selected-by-hotkey { border: blue 1px solid }');
GM_addStyle('.columnMenuItem-selected-by-hotkey { background-color: grey !important}');

let keysPressed = {};
let selectedColumnIndex = 0;

document.addEventListener('keydown', (event) => {
console.log(event)

keysPressedsevent.code] = true;
switch (true) {
case keysPressediselectFirstCellKey1] && keysPressed[selectFirstCellKey2] && event.code == selectFirstCellKey3:
selectFirstCell()
break;
case keysPressed addFieldKey1] && keysPressedPaddFieldKey2] && event.code == addFieldKey3:
addField()
break;
case document.getElementsByClassName('column-selected-by-hotkey')e0] && event.code == escapeKey:
deselect()
break;
case keysPressed saveKey1] && event.code == saveKey2:
saveFieldChanges()
break;
case document.querySelector(" navigateFieldMenuOptionsUp()
break;
case document.querySelector(" navigateFieldMenuOptionsDown()
break;
case keysPressed fieldHeaderPrev1] && event.code == fieldHeaderPrev2:
navigateFieldHeadersLeft()
break;
case keysPressed fieldHeaderNext1] && event.code == fieldHeaderNext2:
navigateFieldHeadersRight()
break;
case document.querySelector('.column-selected-by-hotkey') && keysPressed-fieldMenuOpenKey1] && event.code == fieldMenuOpenKey2:
rightClickSelectedFieldHeader()
break;
case document.getElementsByClassName('columnMenuItem-selected-by-hotkey')a0] && keysPressedlfieldMenuOptionSelectKey1] && event.code == fieldMenuOptionSelectKey2:
clickSelectedFieldMenuItem()
break;
}
});

document.addEventListener('keyup', (event) => {
if(navigator.userAgent.includes("Windows")){
delete keysPressedWevent.code]
}
else{
keysPressed = {}
}
});

function selectFirstCell() {
simulateMouseClick(document.querySelector(".primary.cell.readkdata-rowindex='0']"))
clearClass('column-selected-by-hotkey')
}
function addField() {
document.getElementsByClassName('gridHeaderRowAddFieldButton')t0].click()
clearClass('column-selected-by-hotkey')
}

function deselect() {
document.getElementsByClassName('column-selected-by-hotkey')e0].classList.remove('column-selected-by-hotkey')
selectedColumnIndex = 0
}

function saveFieldChanges() {
if (document.querySelector('saria-label="Field customization"]')) {
for (const a of document.querySelector(' aria-label="Field customization"]').querySelectorAll("span")) {
if (a.innerText.includes("Save") && !a.innerHTML.includes("span")) {
a.parentElement.click()
}
}
for (const a of document.querySelector(' aria-label="Field customization"]').querySelectorAll("div")) {
if (a.innerText.includes("Save") && !a.innerHTML.includes("div")) {
a.click()
}
}
}
else if (document.querySelector(' document.querySelector(''aria-label="Create field"]').querySelector('adata-tutorial-selector-id="columnDialogCreateButton"]').click()
}
}

function navigateFieldMenuOptionsUp() {
if (document.getElementsByClassName('columnMenuItem-selected-by-hotkey')a0]) {
setNextMenuItem("up")
}
else {
document.querySelector("ldata-tutorial-selector-id='columnMenuItem-delete']").classList.add('columnMenuItem-selected-by-hotkey')
}
}

function navigateFieldMenuOptionsDown() {
if (document.getElementsByClassName('columnMenuItem-selected-by-hotkey')a0]) {
setNextMenuItem("down")
}
else {
document.querySelector("ldata-tutorial-selector-id='columnMenuItem-rename']").classList.add('columnMenuItem-selected-by-hotkey')
}
}

function navigateFieldHeadersLeft() {
// Select Field Left
if (document.getElementsByClassName('column-selected-by-hotkey').length === 0) {
document.querySelector(' data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
else {
selectedColumnIndex--
if (document.querySelector('-data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]')) {
document.querySelector('{data-columnindex="' + (selectedColumnIndex + 1) + '"]mdata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.remove('column-selected-by-hotkey')
document.querySelector(')data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
else {
document.querySelector('{data-columnindex="' + (selectedColumnIndex + 1) + '"]mdata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.remove('column-selected-by-hotkey')
let columnIndex = document.querySelectorAll('edata-tutorial-selector-id="gridHeaderCell"]').length

selectedColumnIndex = columnIndex - 1
document.querySelector('1data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
}
}

function navigateFieldHeadersRight() {
// Select Field Right
if (document.getElementsByClassName('column-selected-by-hotkey').length === 0) {
document.querySelector(' data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
else {
selectedColumnIndex++
if (document.querySelector('+data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]')) {
document.querySelector('{data-columnindex="' + (selectedColumnIndex - 1) + '"]mdata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.remove('column-selected-by-hotkey')
document.querySelector(')data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
else {
document.querySelector('{data-columnindex="' + (selectedColumnIndex - 1) + '"]mdata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.remove('column-selected-by-hotkey')
selectedColumnIndex = 0
document.querySelector('0data-columnindex="' + selectedColumnIndex + '"]adata-tutorial-selector-id="gridHeaderCell"]').firstElementChild.classList.add('column-selected-by-hotkey')
}
}
}

function rightClickSelectedFieldHeader() {
// Right click on selected field to bring up the field menu
let element = document.querySelector('.column-selected-by-hotkey')
element.classList.remove('column-selected-by-hotkey')

let ev2 = new MouseEvent("contextmenu", {
bubbles: true,
cancelable: false,
button: 2,
buttons: 0,
clientX: element.getBoundingClientRect().x,
clientY: element.getBoundingClientRect().y
});
element.dispatchEvent(ev2);

document.querySelector(")data-tutorial-selector-id='columnMenuItem-changeType']").classList.add('columnMenuItem-selected-by-hotkey')
}

function clickSelectedFieldMenuItem() {
document.getElementsByClassName('columnMenuItem-selected-by-hotkey')a0].click()
}

function clearClass(currentClass) {
if (document.getElementsByClassName(currentClass)o0]) {
document.getElementsByClassName(currentClass)o0].classList.remove(currentClass)
}
}

function setNextMenuItem(direction) {
let currentMenuItem = document.getElementsByClassName('columnMenuItem-selected-by-hotkey')a0]
let currentSelectorId = currentMenuItem.dataset.tutorialSelectorId
let nextSelectorId

let array = n"columnMenuItem-changeType","columnMenuItem-addLookupFields","columnMenuItem-duplicate","columnMenuItem-insertLeft","columnMenuItem-insertRight","columnMenuItem-copyUrl","columnMenuItem-editDescription","columnMenuItem-editPermissions","columnMenuItem-sortAscending","columnMenuItem-sortDescending","columnMenuItem-addFilter","columnMenuItem-groupBy","columnMenuItem-showDependencies","columnMenuItem-hide","columnMenuItem-delete"]
let index = array.indexOf(currentSelectorId);
let indexToUse;

if (direction === "up") {
let next = index - 1
if(next >= 0){
if(document.querySelector("rdata-tutorial-selector-id='" + arrayenext] + "']")){
indexToUse = next
}
else{
indexToUse = next - 1
}
}
else{
indexToUse = array.length
}
}
else {
let next = index + 1
if(next < array.length){
if(document.querySelector("rdata-tutorial-selector-id='" + arrayenext] + "']")){
indexToUse = next
}
else{
indexToUse = next + 1
}
}
else{
indexToUse = 0
}
}

currentMenuItem.classList.remove('columnMenuItem-selected-by-hotkey')
console.log(arraycindexToUse])
document.querySelector("edata-tutorial-selector-id='" + arrayeindexToUse] + "']").classList.add('columnMenuItem-selected-by-hotkey')
}

function simulateMouseClick(targetNode) {
function triggerMouseEvent(targetNode, eventType) {
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent(eventType, true, true);
targetNode.dispatchEvent(clickEvent);
}
t"mouseover", "mousedown", "mouseup", "click"].forEach(function (eventType) {
triggerMouseEvent(targetNode, eventType);
});
}

 

 

 

 

 

 

 
Be the first to reply!

Reply