Skip to content

Instantly share code, notes, and snippets.

@aleclarson
Last active March 20, 2025 15:37
Show Gist options
  • Save aleclarson/8fe6d7de203407f2289c0b0d41ec9e9a to your computer and use it in GitHub Desktop.
Save aleclarson/8fe6d7de203407f2289c0b0d41ec9e9a to your computer and use it in GitHub Desktop.
Shift+Click to Block – X.com
// ==UserScript==
// @name X.com ~ Easy Block
// @namespace http://tampermonkey.net/
// @version 2025-03-20
// @description Block a tweet author with shift-click. Mark as "not interested" with option-click.
// @author Alec Larson
// @match https://x.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=x.com
// @grant none
// @source https://gist.github.com/aleclarson/8fe6d7de203407f2289c0b0d41ec9e9a
// ==/UserScript==
; (function () {
'use strict'
const debug = true
function log(...args) {
debug && console.log('[shift-block]', ...args)
}
/** @type {HTMLDivElement} */
let tweet
document.addEventListener(
'mouseover',
(e) => {
const current = tweet
tweet = e.target.closest('[data-testid="tweet"]')
if (current !== tweet) {
if (tweet) {
log('mouseover tweet by', tweet.querySelectorAll('a')[2]?.textContent)
} else {
log('mouseout tweet')
}
}
},
{ capture: true },
)
document.addEventListener(
'mouseout',
(e) => {
if (tweet && !e.target.closest('[data-testid="tweet"]')) {
log('mouseout tweet')
tweet = null
}
},
{ capture: true },
)
document.addEventListener(
'click',
(e) => {
if (!tweet) return
if (
e.button === 0 &&
!e.ctrlKey &&
!e.metaKey &&
(e.shiftKey && !e.altKey) ||
(e.altKey && !e.shiftKey)
) {
e.preventDefault()
e.stopPropagation()
const moreBtn = tweet.querySelector(
'[aria-haspopup="menu"][aria-label="More"]',
)
log('%s+click detected', e.shiftKey ? 'shift' : 'option')
moreBtn.click()
// Clear the text selection caused by shift-clicking.
window.getSelection().removeAllRanges()
setTimeout(() => {
const textSelector = e.shiftKey ? 'Block' : 'Not interested in this post'
const actionBtn = Array.from(
document.querySelectorAll('[role="menu"] [role="menuitem"]'),
).find((e) => e.textContent.includes(textSelector))
if (actionBtn) {
actionBtn.click()
if (e.shiftKey) {
setTimeout(() => {
const confirmBtn = document.querySelector('[data-testid="confirmationSheetConfirm"]')
if (confirmBtn) {
confirmBtn.click()
log('blocked %s', tweet.querySelectorAll('a')[2]?.textContent)
} else {
log('confirm button not found')
}
}, 50)
}
} else {
log('"%s" button not found', textSelector)
}
}, 50)
}
},
{ capture: true },
)
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment