Accessibility / Keyboard / Skip Link Validator
The Skip Link Validator bookmarklet analyzes skip navigation links that allow keyboard users to bypass repetitive content. Finds all anchor links with href starting with "#", identifies which are actual skip links (containing keywords like "skip", "jump", "main content"), validates that links have accessible names (visible text, aria-label, or title), and checks if target elements exist. Displays a panel showing whether the first link on the page is a skip link (best practice), lists all skip links found with their validation status, and highlights elements on hover. Run again to remove.
WCAG SC 2.4.1: Bypass Blocks
Run Skip Link Validator
Test run or drag to
bookmarklets bar to install
javascript:%21function()%7B%22use%20strict%22%3Btry%7Bconst%20n%3Ddocument.getElementById(%22skip-link-validator-host%22)%3Bn%26%26n.remove()%3Bconst%20e%3Ddocument.createElement(%22div%22)%3Be.id%3D%22skip-link-validator-host%22%2Ce.style.cssText%3D%22position%3Afixed%3Btop%3A10px%3Bright%3A10px%3Bz-index%3A999999%3Bwidth%3A400px%3Bmax-height%3A80vh%3Boverflow%3Aauto%3B%22%2Cdocument.body.appendChild(e)%3Bconst%20s%3De.attachShadow(%7Bmode%3A%22open%22%7D)%2Ct%3Ddocument.createElement(%22style%22)%3Bt.textContent%3D%22%5Cn%20%20%20%20%20%20*%20%7B%20box-sizing%3A%20border-box%3B%20%7D%5Cn%20%20%20%20%20%20.slv-panel%20%7B%5Cn%20%20%20%20%20%20%20%20font-family%3A%20-apple-system%2C%20BlinkMacSystemFont%2C%20%27Segoe%20UI%27%2C%20Roboto%2C%20sans-serif%3B%5Cn%20%20%20%20%20%20%20%20background%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20border%3A%202px%20solid%20%23333%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%208px%3B%5Cn%20%20%20%20%20%20%20%20box-shadow%3A%200%204px%2020px%20rgba(0%2C0%2C0%2C0.3)%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-header%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23333%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%2016px%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20justify-content%3A%20space-between%3B%5Cn%20%20%20%20%20%20%20%20align-items%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%206px%206px%200%200%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-title%20%7B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20600%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.875rem%3B%5Cn%20%20%20%20%20%20%20%20margin%3A%200%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-close%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20none%3B%5Cn%20%20%20%20%20%20%20%20border%3A%20none%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%201.25rem%3B%5Cn%20%20%20%20%20%20%20%20cursor%3A%20pointer%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%200%3B%5Cn%20%20%20%20%20%20%20%20width%3A%2028px%3B%5Cn%20%20%20%20%20%20%20%20height%3A%2028px%3B%5Cn%20%20%20%20%20%20%20%20display%3A%20flex%3B%5Cn%20%20%20%20%20%20%20%20align-items%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20justify-content%3A%20center%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%204px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-close%3Ahover%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20rgba(255%2C255%2C255%2C0.2)%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-content%20%7B%5Cn%20%20%20%20%20%20%20%20padding%3A%2016px%3B%5Cn%20%20%20%20%20%20%20%20max-height%3A%2060vh%3B%5Cn%20%20%20%20%20%20%20%20overflow-y%3A%20auto%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-summary%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23f5f5f5%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%206px%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%2016px%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.875rem%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-summary%20strong%20%7B%5Cn%20%20%20%20%20%20%20%20display%3A%20block%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%208px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-item%20%7B%5Cn%20%20%20%20%20%20%20%20padding%3A%2010px%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%208px%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%204px%3B%5Cn%20%20%20%20%20%20%20%20border-left%3A%204px%20solid%20%23ccc%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.8125rem%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-item.pass%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23e6ffed%3B%5Cn%20%20%20%20%20%20%20%20border-left-color%3A%20%2328a745%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-item.fail%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23ffe6e6%3B%5Cn%20%20%20%20%20%20%20%20border-left-color%3A%20%23dc3545%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-item.warning%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23fff3cd%3B%5Cn%20%20%20%20%20%20%20%20border-left-color%3A%20%23ffc107%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-text%20%7B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20600%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%204px%3B%5Cn%20%20%20%20%20%20%20%20word-break%3A%20break-all%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-href%20%7B%5Cn%20%20%20%20%20%20%20%20color%3A%20%23666%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.75rem%3B%5Cn%20%20%20%20%20%20%20%20margin-bottom%3A%204px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-link-message%20%7B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.75rem%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-badge%20%7B%5Cn%20%20%20%20%20%20%20%20display%3A%20inline-block%3B%5Cn%20%20%20%20%20%20%20%20padding%3A%202px%208px%3B%5Cn%20%20%20%20%20%20%20%20border-radius%3A%2012px%3B%5Cn%20%20%20%20%20%20%20%20font-size%3A%200.6875rem%3B%5Cn%20%20%20%20%20%20%20%20font-weight%3A%20600%3B%5Cn%20%20%20%20%20%20%20%20margin-right%3A%206px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-badge.skip%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%23007bff%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-badge.first%20%7B%5Cn%20%20%20%20%20%20%20%20background%3A%20%2328a745%3B%5Cn%20%20%20%20%20%20%20%20color%3A%20white%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.slv-highlight%20%7B%5Cn%20%20%20%20%20%20%20%20outline%3A%203px%20dashed%20%23ffc107%20%21important%3B%5Cn%20%20%20%20%20%20%20%20outline-offset%3A%202px%3B%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%22%2Cs.appendChild(t)%3Bconst%20i%3Ddocument.createElement(%22div%22)%3Bi.className%3D%22slv-panel%22%2Cs.appendChild(i)%3Bconst%20l%3D%7BskipLinks%3A%5B%5D%2CfirstLinkIsSkip%3A%211%2Cissues%3A%5B%5D%7D%2Co%3DArray.from(document.querySelectorAll(%22a%5Bhref%5D%22))%2Ca%3Do.filter(n%3D%3E%7Bconst%20e%3Dn.getAttribute(%22href%22)%3Breturn%20e%26%26e.startsWith(%22%23%22)%7D)%3Bo.length%3E0%26%26a.length%3E0%26%26(l.firstLinkIsSkip%3Do%5B0%5D%3D%3D%3Da%5B0%5D)%2Ca.forEach((n%2Ce)%3D%3E%7Bconst%20s%3Dn.getAttribute(%22href%22)%2Ct%3D0%3D%3D%3De%2Ci%3D0%3D%3D%3Do.indexOf(n)%2Ca%3D%7Belement%3An%2Chref%3As%2Ctext%3An.textContent.trim()%2CariaLabel%3An.getAttribute(%22aria-label%22)%2CisFirst%3At%2CisFirstOverall%3Ai%2ChasIssue%3A%211%2Cissue%3Anull%7D%2Cr%3Dn.textContent.trim()%2Cd%3Dn.getAttribute(%22aria-label%22)%2Cc%3Dn.getAttribute(%22aria-labelledby%22)%2Cp%3Dn.getAttribute(%22title%22)%3Br%7C%7Cd%7C%7Cc%7C%7Cp%7C%7C(a.hasIssue%3D%210%2Ca.issue%3D%22Skip%20link%20lacks%20accessible%20name%20(no%20visible%20text%2C%20aria-label%2C%20or%20title)%22%2Cl.issues.push(a.issue))%3Bconst%20u%3Ds.substring(1)%3Bdocument.getElementById(u)%7C%7Cdocument.querySelector(%60%5Bname%3D%22%24%7Bu%7D%22%5D%60)%7C%7C(a.hasIssue%3D%210%2Ca.issue%3D%60Skip%20link%20target%20%23%24%7Bu%7D%20does%20not%20exist%60%2Cl.issues.push(a.issue))%3Bconst%20k%3D%5B%22skip%22%2C%22jump%22%2C%22main%20content%22%2C%22navigation%22%2C%22menu%22%5D.some(n%3D%3E(r%2B%22%20%22%2B(d%7C%7C%22%22)%2B%22%20%22%2B(p%7C%7C%22%22)).toLowerCase().includes(n))%3Ba.isSkipLink%3Dk%2Cl.skipLinks.push(a)%7D)%2Co.length%3E0%26%26%21l.firstLinkIsSkip%26%26l.issues.push(%22First%20link%20in%20page%20is%20not%20a%20skip%20link%20-%20keyboard%20users%20must%20tab%20through%20all%20navigation%22)%3Blet%20r%3D%60%5Cn%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-header%22%3E%5Cn%20%20%20%20%20%20%20%20%3Ch2%20class%3D%22slv-title%22%3ESkip%20Link%20Validator%3C%2Fh2%3E%5Cn%20%20%20%20%20%20%20%20%3Cbutton%20class%3D%22slv-close%22%20aria-label%3D%22Close%22%20onclick%3D%22document.getElementById(%27skip-link-validator-host%27).remove()%22%3E%26times%3B%3C%2Fbutton%3E%5Cn%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-content%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-summary%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cstrong%3ESummary%3A%3C%2Fstrong%3E%5Cn%20%20%20%20%20%20%20%20%20%20Found%20%24%7Ba.length%7D%20skip%20link(s)%20(href%20starts%20with%20%23)%3Cbr%3E%5Cn%20%20%20%20%20%20%20%20%20%20%24%7Bl.firstLinkIsSkip%3F%27%3Cspan%20style%3D%22color%3A%2328a745%22%3E%5Cu2713%20First%20link%20is%20a%20skip%20link%3C%2Fspan%3E%27%3A%27%3Cspan%20style%3D%22color%3A%23dc3545%22%3E%5Cu2717%20First%20link%20is%20NOT%20a%20skip%20link%3C%2Fspan%3E%27%7D%3Cbr%3E%5Cn%20%20%20%20%20%20%20%20%20%20%24%7B0%3D%3D%3Dl.issues.length%3F%27%3Cspan%20style%3D%22color%3A%2328a745%22%3ENo%20issues%20found%3C%2Fspan%3E%27%3A%60%3Cspan%20style%3D%22color%3A%23dc3545%22%3E%24%7Bl.issues.length%7D%20issue(s)%20found%3C%2Fspan%3E%60%7D%5Cn%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%60%3Bl.skipLinks.length%3E0%3F(r%2B%3D%27%3Cdiv%20style%3D%22font-weight%3A600%3Bmargin-bottom%3A8px%22%3ESkip%20Links%20Found%3A%3C%2Fdiv%3E%27%2Cl.skipLinks.forEach(n%3D%3E%7Bconst%20e%3Dn.hasIssue%3F%22fail%22%3A%22pass%22%3Blet%20s%3D%22%22%3Bn.isFirstOverall%26%26(s%2B%3D%27%3Cspan%20class%3D%22slv-badge%20first%22%3EFirst%20Link%3C%2Fspan%3E%27)%2Cn.isSkipLink%26%26(s%2B%3D%27%3Cspan%20class%3D%22slv-badge%20skip%22%3ESkip%20Link%3C%2Fspan%3E%27)%2Cr%2B%3D%60%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-link-item%20%24%7Be%7D%22%20onmouseover%3D%22document.querySelector(%27a%5Bhref%3D%5C%5C%22%24%7Bn.href%7D%5C%5C%22%5D%27).classList.add(%27slv-highlight%27)%22%20onmouseout%3D%22document.querySelector(%27a%5Bhref%3D%5C%5C%22%24%7Bn.href%7D%5C%5C%22%5D%27).classList.remove(%27slv-highlight%27)%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-link-text%22%3E%24%7Bs%7D%24%7Bn.text%7C%7C%22(no%20text)%22%7D%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22slv-link-href%22%3Ehref%3A%20%22%24%7Bn.href%7D%22%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%24%7Bn.ariaLabel%3F%60%3Cdiv%20class%3D%22slv-link-href%22%3Earia-label%3A%20%22%24%7Bn.ariaLabel%7D%22%3C%2Fdiv%3E%60%3A%22%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%24%7Bn.issue%3F%60%3Cdiv%20class%3D%22slv-link-message%22%20style%3D%22color%3A%23dc3545%22%3E%5Cu26a0%20%24%7Bn.issue%7D%3C%2Fdiv%3E%60%3A%27%3Cdiv%20class%3D%22slv-link-message%22%20style%3D%22color%3A%2328a745%22%3E%5Cu2713%20Valid%20skip%20link%3C%2Fdiv%3E%27%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%20%20%20%20%60%7D))%3Ar%2B%3D%27%3Cdiv%20style%3D%22color%3A%23666%3Bfont-style%3Aitalic%22%3ENo%20skip%20links%20found%20on%20this%20page.%3C%2Fdiv%3E%27%2Cr%2B%3D%22%5Cn%20%20%20%20%20%20%3C%2Fdiv%3E%5Cn%20%20%20%20%22%2Ci.innerHTML%3Dr%3Bconst%20d%3Ddocument.createElement(%22style%22)%3Bd.id%3D%22slv-highlight-style%22%2Cd.textContent%3D%22.slv-highlight%20%7B%20outline%3A%203px%20dashed%20%23ffc107%20%21important%3B%20outline-offset%3A%202px%20%21important%3B%20%7D%22%2Cdocument.head.appendChild(d)%2Cconsole.log(%22%5BSkip%20Link%20Validator%5D%20-%20Analysis%20complete%22)%7Dcatch(n)%7Balert(%22Bookmarklet%20Error%3A%20%22%2Bn.message)%7D%7D()%2Cconsole.log(%22%5CnSource%3A%20https%3A%2F%2Fgithub.com%2Fpattespatte%2Fpublic-bookmarklets%2F%5CnBookmarklet%20name%3A%20Skip%20Link%20Validator%5Cn%22)%3B
← Back to all bookmarklets