← Back to Articles

Solo-Clicking GitHub's PR File Filter

Solo-Clicking GitHub's PR File Filter

Large PRs come with large file lists. If your project mixes source files with generated metadata, assets, or config, the GitHub extension filter quickly becomes a chore. You want to review one file type. GitHub has no built-in way to solo it. No "select only this" option. You're unchecking a dozen others to get there. Every. Single. Time.

I got tired of it. So I fixed it.

The idea

Alt+Click any extension → everything else disappears. One click, instant filter, no reload.

Simple enough concept. The implementation took some digging.

Getting there

GitHub's filter is a React component, which means the usual tricks don't work. .click() on list items is silently ignored. URL rewrites cause a full page reload. Workable, but slow. history.pushState updates the URL but React doesn't react to it.

The actual solution: walk up the React fiber tree from the dropdown's DOM element until you find the component that owns the filter state. It has a function called setFileFilterState. Call it directly with all other extensions marked unselected, and the file list updates instantly. No navigation, no reload.

function getFilterProps() {
  const el = document.querySelector('.prc-ActionList-ActionList-rPFF2');
  if (!el) return null;
  const fiber = el[Object.keys(el).find(k => k.startsWith('__reactFiber'))];
  let node = fiber;
  for (let i = 0; i < 50; i++) {
    if (node?.memoizedProps?.setFileFilterState) return node.memoizedProps;
    node = node?.return;
    if (!node) break;
  }
  return null;
}

Once you have it, soloing an extension is one call:

const allExts = Object.keys(props.fileFilterState.fileExtensions);
props.setFileFilterState({
  ...props.fileFilterState,
  unselectedFileExtensions: new Set(allExts.filter(e => e !== '.cs'))
});

Setup

  1. Install Tampermonkey
  2. Create a new script, paste the code below, save
  3. Make sure Tampermonkey has permission to run on github.com. Easy to miss, and it will silently break everything

Full script

// ==UserScript==
// @name         GitHub PR Filter - Solo Click
// @namespace    http://tampermonkey.net/
// @version      1.0
// @match        *://*/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  function getFilterProps() {
    const el = document.querySelector('.prc-ActionList-ActionList-rPFF2');
    if (!el) return null;
    const fiber = el[Object.keys(el).find(k => k.startsWith('__reactFiber'))];
    let node = fiber;
    for (let i = 0; i < 50; i++) {
      if (node?.memoizedProps?.setFileFilterState && node?.memoizedProps?.fileFilterState) {
        return node.memoizedProps;
      }
      node = node?.return;
      if (!node) break;
    }
    return null;
  }

  document.addEventListener('click', function(e) {
    if (!e.altKey) return;
    const item = e.target.closest('.prc-ActionList-ActionListItem-So4vC');
    if (!item) return;
    const text = item.innerText?.trim().split('\n')[0];
    if (!text || !text.startsWith('.')) return;
    e.preventDefault();
    e.stopPropagation();
    const props = getFilterProps();
    if (!props) return;
    const allExts = Object.keys(props.fileFilterState.fileExtensions);
    props.setFileFilterState({
      ...props.fileFilterState,
      unselectedFileExtensions: new Set(allExts.filter(e => e !== text))
    });
  }, true);
})();

Usage: open the extension filter on any PR, hold Alt, click any extension. Done.

⚠️ GitHub's class names change occasionally. If it stops working, inspect the dropdown and update the two .prc-ActionList-* selectors to whatever GitHub is using now.