Skip to content

Instantly share code, notes, and snippets.


Fotis Papadogeorgopoulos fpapado

View GitHub Profile
fpapado /
Last active Mar 8, 2021
Duolingo (more) Accessible Styles


Install directly with Stylus

To install this stylesheet, you will need a userstyle extension. For example:

Then, you will need to open the link below, which the extension will pick up and prompt you to install:

fpapado /
Last active Jun 22, 2021
:focus-visible progressive enhancement mixin

Find the full post on

:focus-visible is a standard way of only showing focus styles for keyboard and focus-based modalities. When using it, however, you must take care to not remove :focus altogether, where :focus-visible is not supported.

With CSS, we can achieve progressive enhancement of :focus to :focus-visible:

/* Styles where only focus is supported */
fpapado /
Last active Jan 15, 2021
Validating URLs with the URL constructor

Validating URLs is hard! On the face of it, you could use a RegEx to match on the URL structure, but that is likely only going to match a narrow subset of URLs, whether intentionally or accidentally.

Beyond having a "valid" URL, an application might be applying extra conditions on top. For example, accepting only http: or https: URLs, but not file: and others. This might be ok depending on the application, but knowing that takes some active design work to figure out. For the purpose of handling user errors, and offering suggestions, it also helps to know in what manner the URL failed validation. For example, we might be able to offer precise suggestions for our application-specific errors, while general URL parsing issues can be out of scope.

To make life easier, let's separate the term "valid" and "invalid" into a few different ones:

  • Valid URL: a URL that can be parsed successfully according to the standard (which, uhm, I am reluctant to dive into, or rather I feel unqualified to give you an overvi
fpapado / state.njk
Last active Mar 28, 2020
Roasters by State
View state.njk
pagination: {
// Go over the roaster data
data: "roasters",
// Convert the list of roaster to {[state]: {name: string, roasters: Array<Roaster>}}
// (You could do without the {name, roasters} and only have data, but then the iteration is uglier imo)
before: function(roasters) {
let roastersByState = {};
for (let roaster of roasters) {
View 0_useLeftRightAutoPosition.tsx
import {useLayoutEffect, useState} from 'react';
* React Hook to measure a DOM element and set its `position` depending on
* whether it would overflow left or right.
* Uses useLayoutEffect for batched DOM measurements and painting.
* @param toggle a boolean on whether to run the effect. Runs cleanup when it changes.
* You might want a toggle if the element is always present in the DOM, and its display toggled.
fpapado / split_panels.js
Created Jul 23, 2018
SpeedCurve split panels
View split_panels.js
(function() {
'use strict';
// Your code here...
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
View SketchSystems.spec
publish -> Published
unpublish -> Unpublished
event exists -> Event
no event exists -> No Event
fpapado / FauxButton.tsx
Last active Jul 12, 2018
Accessible `<button>` usurper
View FauxButton.tsx
import React from "react";
* Accessible "button" usurper.
* Establishes the correct role, tabindex, and key/mouse interaction if interactive.
* Buttons activate on space and enter.
* NOTE: Gives 'disabled' attribute if interaction not provided.
* @see
fpapado / graphana_pride.css
Created Jun 27, 2018
Grafana Custom CSS for Pride
View graphana_pride.css
.scroll-canvas--dashboard {
background: linear-gradient(180deg, #f00000, #f00000 16.67%, #ff8000 16.67%, #ff8000 33.33%, #ffff00 33.33%, #ffff00 50%, #007940 50%, #007940 66.67%, #4040ff 66.67%, #4040ff 83.33%, #a000c0 83.33%, #a000c0) fixed;
fpapado / 01_failing.js
Created Mar 18, 2018
nanotiming overlapping timers
View 01_failing.js
// Three operations (loops for simplicity).
// We want to time the first two separately and all three of them together.
// Ideally, the ordering of starting the timers would not matter.
// This case fails because the timer for the first two loops is started first
var nanotiming = require('nanotiming')
try {
var performance = require('perf_hooks').performance
var timeFirstTwo = nanotiming('my-loop')