Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="top" class="wrapper">
    <h1>Which Colemak is which?</h1>
    <div id="output"></div>
    <p>Still have questions? Come ask us in the <a href="https://discord.gg/3VsHDG86hM" target="_blank">Colemak Community Discord Server</a>!</p>
</div>
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css2?family=Lato&display=swap');

*, *::before, *::after { box-sizing: border-box; }

html {
    background-color: #fff;
    font: 14px 'Lato', 'Arial', sans-serif;
    color: #222;
    
    @media (min-width: 768px) {
        font-size: 19px;
    }
}

body {
    max-width: 65rem;
    margin: 0 auto;
}

dl {
    dt {
        margin-top: 1rem;
        font-weight: bold;
    }
    
    dd {
        margin-left: 3rem;
        
        @media (min-width: 768px) {
            margin-left: 2.8rem;
        }
    }
}

dt > label,
h3 > label {
    display: flex;
    align-items: center;
    border-radius: 0.5rem;
    padding: 0.5rem 0;
    background-color: #e3f1f7;
    transition: all 0.1s ease;
    
    > input {
        margin: 0 1rem;
    }
    
    &:active,
    &:hover {
        background-color: #0375aa;
        color: #eee;
    }
}

code {
    background-color: #eee;
}

a {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    border-radius: 0.25rem;
    background-color: #e3f1f7;
    color: inherit;
    text-decoration: none;
    transition: all 0.1s ease;
    
    &:active,
    &:hover {
        background-color: #0375aa;
        color: #eee;
    }
}

.wrapper {
    padding: 0.25rem;
    scroll-behavior: 'auto';

    &.animated {
        scroll-behavior: 'smooth';
    }
}

.container-generated {
    min-width: 320px;
    max-width: 100%;
    overflow-x: auto;
    padding-bottom: 0.5rem;
}

.container,
.hand {
    display: flex;
}

.hand {
    margin: 0 0.5rem 0 0;
}

.col {
    display: flex;
    flex-direction: column;
}
.col-d1 {
    margin-top: 1rem;
}
.col-d1-5 {
    margin-top: 1.5rem;
}
.col-d2 {
    margin-top: 2rem;
}
.col-d3 {
    margin-top: 3rem;
}

.key {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    padding: 0.3rem;
    width: 7.8vw;
    height: 7.8vw;
    margin: 0.15vw;
    border: 1px solid #bbb;
    border-radius: 0.6rem;
    box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.3);
    background-color: #f5f5f5;
    overflow: hidden;
    vertical-align: top;
    text-align: center;
    text-transform: uppercase;
    color: #333;
    font-size: 5.5vw;
    
    @media (min-width: 768px) {
        padding: 0.5rem;
        width: 3rem;
        height: 3rem;
        margin: 0.2rem;
        font-size: 2rem;
    }
    
    &.homing {
        border-color: #999;
        font-weight: bold;
        box-shadow: 1px 1px 7px 2px rgba(0, 0, 0, 0.6);
        text-decoration: underline;
    }
    
    &.pinky {
        background-color: #a0dbcb;
    }
    
    &.ring {
        background-color: #d8b6d8;
    }
    
    &.middle {
        background-color: #e0d5ac;
    }
    
    &.index {
        background-color: #a8bbdb;
    }
}

.container-row {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;

    &.row-d-quarter {
        margin-left: 1.95vw;
    }
    
    &.row-d-half {
        margin-left: 3.9vw;
    }
    
    &.row-d-three-quarters {
        margin-left: 5.85vw;
    }
    
    @media (min-width: 768px) {
        &.row-d-quarter {
            margin-left: 0.7rem;
        }

        &.row-d-half {
            margin-left: 1.4rem;
        }

        &.row-d-three-quarters {
            margin-left: 2.1rem;
        }
    }
}

.legend {
    list-style-type: none;
    padding-left: 0;
}
              
            
!

JS

              
                const LAYOUTS = {
    vanilla: [
        {key: 'q', finger: 'pinky'}, {key: 'w', finger: 'ring'}, {key: 'f', finger: 'middle'}, {key: 'p', finger: 'index'}, {key: 'g', finger: 'index'}, {key: 'j', finger: 'index'}, {key: 'l', finger: 'index'}, {key: 'u', finger: 'middle'}, {key: 'y', finger: 'ring'}, {key: ';', finger: 'pinky'},
        {key: 'a', finger: 'pinky'}, {key: 'r', finger: 'ring'}, {key: 's', finger: 'middle'}, {key: 't', finger: 'index'}, {key: 'd', finger: 'index'}, {key: 'h', finger: 'index'}, {key: 'n', finger: 'index'}, {key: 'e', finger: 'middle'}, {key: 'i', finger: 'ring'}, {key: 'o', finger: 'pinky'},
        {key: 'z', finger: 'pinky'}, {key: 'x', finger: 'ring'}, {key: 'c', finger: 'middle'}, {key: 'v', finger: 'index'}, {key: 'b', finger: 'index'}, {key: 'k', finger: 'index'}, {key: 'm', finger: 'index'}, {key: ',', finger: 'middle'}, {key: '.', finger: 'ring'}, {key: '/', finger: 'pinky'},
    ],
    dh_ortho: [
        {key: 'q', finger: 'pinky'}, {key: 'w', finger: 'ring'}, {key: 'f', finger: 'middle'}, {key: 'p', finger: 'index'}, {key: 'b', finger: 'index'}, {key: 'j', finger: 'index'}, {key: 'l', finger: 'index'}, {key: 'u', finger: 'middle'}, {key: 'y', finger: 'ring'}, {key: ';', finger: 'pinky'},
        {key: 'a', finger: 'pinky'}, {key: 'r', finger: 'ring'}, {key: 's', finger: 'middle'}, {key: 't', finger: 'index'}, {key: 'g', finger: 'index'}, {key: 'm', finger: 'index'}, {key: 'n', finger: 'index'}, {key: 'e', finger: 'middle'}, {key: 'i', finger: 'ring'}, {key: 'o', finger: 'pinky'},
        {key: 'z', finger: 'pinky'}, {key: 'x', finger: 'ring'}, {key: 'c', finger: 'middle'}, {key: 'd', finger: 'index'}, {key: 'v', finger: 'index'}, {key: 'k', finger: 'index'}, {key: 'h', finger: 'index'}, {key: ',', finger: 'middle'}, {key: '.', finger: 'ring'}, {key: '/', finger: 'pinky'},
    ],
    dh_iso: [
        {key: 'q', finger: 'pinky'}, {key: 'w', finger: 'ring'}, {key: 'f', finger: 'middle'}, {key: 'p', finger: 'index'}, {key: 'b', finger: 'index'}, {key: 'j', finger: 'index'}, {key: 'l', finger: 'index'}, {key: 'u', finger: 'middle'}, {key: 'y', finger: 'ring'}, {key: ';', finger: 'pinky'},
        {key: 'a', finger: 'pinky'}, {key: 'r', finger: 'ring'}, {key: 's', finger: 'middle'}, {key: 't', finger: 'index'}, {key: 'g', finger: 'index'}, {key: 'm', finger: 'index'}, {key: 'n', finger: 'index'}, {key: 'e', finger: 'middle'}, {key: 'i', finger: 'ring'}, {key: 'o', finger: 'pinky'},
        {key: 'z', finger: 'pinky'}, {key: 'x', finger: 'ring'}, {key: 'c', finger: 'middle'}, {key: 'd', finger: 'index'}, {key: 'v', finger: 'index'}, {key: '\\', finger: 'index'}, {key: 'k', finger: 'index'}, {key: 'h', finger: 'index'}, {key: ',', finger: 'middle'}, {key: '.', finger: 'ring'}, {key: '/', finger: 'pinky'},
    ],
    dh_ansi: [
        {key: 'q', finger: 'pinky'}, {key: 'w', finger: 'ring'}, {key: 'f', finger: 'middle'}, {key: 'p', finger: 'index'}, {key: 'b', finger: 'index'}, {key: 'j', finger: 'index'}, {key: 'l', finger: 'index'}, {key: 'u', finger: 'middle'}, {key: 'y', finger: 'ring'}, {key: ';', finger: 'pinky'},
        {key: 'a', finger: 'pinky'}, {key: 'r', finger: 'ring'}, {key: 's', finger: 'middle'}, {key: 't', finger: 'index'}, {key: 'g', finger: 'index'}, {key: 'm', finger: 'index'}, {key: 'n', finger: 'index'}, {key: 'e', finger: 'middle'}, {key: 'i', finger: 'ring'}, {key: 'o', finger: 'pinky'},
        {key: 'x', finger: 'ring'}, {key: 'c', finger: 'middle'}, {key: 'd', finger: 'index'}, {key: 'v', finger: 'index'}, {key: 'z', finger: 'index'}, {key: 'k', finger: 'index'}, {key: 'h', finger: 'index'}, {key: ',', finger: 'middle'}, {key: '.', finger: 'ring'}, {key: '/', finger: 'pinky'},
    ],
};

const RowTemplate = () => (
    <div className="container container-ansi container-row">
        <div className="row">
            {Array.from({length: 10}).map(() => (
                <span className="key"></span>
            ))}
        </div>
        <div className="row row-d-quarter">
            {Array.from({length: 10}).map((_, index) => (
                <span className={`key${index === 3 || index === 6 ? ' homing' : ''}`}></span>
            ))}
        </div>
        <div className="row row-d-three-quarters">
            {Array.from({length: 10}).map(() => (
                <span className="key"></span>
            ))}
        </div>
    </div>
);

const RowIsoTemplate = () => (
    <div className="container container-row container-iso">
        <div className="row row-d-quarter">
            {Array.from({length: 10}).map(() => (
                <span className="key"></span>
            ))}
        </div>
        <div className="row row-d-half">
            {Array.from({length: 10}).map((_, index) => (
                <span className={`key${index === 3 || index === 6 ? ' homing' : ''}`}></span>
            ))}
        </div>
        <div className="row">
            {Array.from({length: 11}).map(() => (
                <span className="key"></span>
            ))}
        </div>
    </div>
);

const ColTemplate = () => (
    <>
        <h4>Ortholinear looks like this</h4>
        <div className="container container-row">
            <div className="row">
                {Array.from({length: 10}).map(() => (
                    <span className="key"></span>
                ))}
            </div>
            <div className="row">
                {Array.from({length: 10}).map((_, index) => (
                <span className={`key${index === 3 || index === 6 ? ' homing' : ''}`}></span>
            ))}
            </div>
            <div className="row">
                {Array.from({length: 10}).map(() => (
                    <span className="key"></span>
                ))}
            </div>
        </div>
        <h4>Columnar stagger looks like this</h4>
        <div className="container">
            <div className="hand">
                <div className="col col-d2">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d1">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d1">
                    <span className="key"></span>
                    <span className="key homing"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d1-5">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
            </div>
            <div className="hand">
                <div className="col col-d1-5">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d1">
                    <span className="key"></span>
                    <span className="key homing"></span>
                    <span className="key"></span>
                </div>
                <div className="col">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d1">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
                <div className="col col-d2">
                    <span className="key"></span>
                    <span className="key"></span>
                    <span className="key"></span>
                </div>
            </div>
        </div>
    </>
);

const Component = () => {
    const [keyboardType, setKeyboardType] = React.useState(undefined);
    const [layoutType, setLayoutType] = React.useState(undefined);
    const prefersReducedMotionRef = React.useRef();
    
    React.useEffect(() => {
        prefersReducedMotionRef.current = window.matchMedia('(prefers-reduced-motion: reduce), (update: slow)').matches;
        
        if (!prefersReducedMotionRef.current) {
            document.getElementById('top').classList.add('animated');
        }
    }, []);
    
    function generateLayout(keyboard, layout) {
        const layoutData = layout === 'vanilla'
            ? LAYOUTS.vanilla
            : LAYOUTS[`dh_${keyboard}`];
        
        const numBottomRow = keyboard === 'iso' && layout !== 'vanilla' ? 31 : 30;
        
        return (
            <div
                className={classNames(
                    'container',
                    'container-row',
                    'container-generated',
                )}
            >
                {[[0, 10], [10, 20], [20, numBottomRow]].map(([start, end], rowIndex) => {
                    return (
                        <div
                            className={classNames(
                                'row',
                                keyboard === 'ansi' && rowIndex === 1 && 'row-d-quarter',
                                keyboard === 'ansi' && rowIndex === 2 && 'row-d-three-quarters',
                                keyboard === 'iso' && rowIndex === 0 && 'row-d-quarter',
                                keyboard === 'iso' && rowIndex === 1 && 'row-d-half',
                            )}
                        >
                            {keyboard === 'iso' && rowIndex === 2 && layout === 'vanilla' && (
                                <span className="key pinky" title="pinky finger">\</span>
                            )}
                            {layoutData.slice(start, end).map((keyData, layoutIndex) => (
                                <span
                                    className={classNames(
                                        'key',
                                        rowIndex === 1 && (layoutIndex === 3 || layoutIndex === 6) && 'homing',
                                        keyData.finger,
                                    )}
                                    title={`${keyData.finger} finger`}
                                >
                                    {keyData.key}
                                </span>
                            ))}
                        </div>
                    );
                })}
            </div>
        )
    }
    
    const scrollToEle = (id) => {
        document.getElementById(id).scrollIntoView({
            behavior: prefersReducedMotionRef.current ? 'auto' : 'smooth',
        });
    };
    
    const GENERATED_BLURB = {
        vanilla: "Vanilla Colemak.",
        dh: {
            ortho: "Colemak DH (Colemak Curl).",
            iso: "Colemak DH (Colemak Curl Angle).",
            ansi: "Colemak DH (Colemak Curl Angle).",
        }
    };

    return (
        <>
            <h2>First, pick your keyboard type:</h2>
            <h3><label onClick={() => { setKeyboardType('ansi'); scrollToEle('variants'); }}><input type="radio" name="board-type" id="board-rowstag" value="rowstag" /> ANSI row stagger</label></h3>
            <RowTemplate />
            <h3><label onClick={() => { setKeyboardType('iso'); scrollToEle('variants'); }}><input type="radio" name="board-type" id="board-iso" value="iso" /> ISO row stagger (or split left shift)</label></h3>
            <RowIsoTemplate />
            <h3><label onClick={() => { setKeyboardType('ortho'); scrollToEle('variants'); }}><input type="radio" name="board-type" id="board-colstag" value="colstag-ortho" /> Ortholinear or Columnar stagger</label></h3>
            <ColTemplate />
            <h2 id="variants">Next, choose a variant:</h2>
            <dl>
                <dt><label onClick={() => { setLayoutType('vanilla'); scrollToEle('final-layout'); }}>
                    <input type="radio" name="layout" value="vanilla" />
                    Vanilla Colemak
                </label></dt>
                <dd>Colemak is a modern alternative to the QWERTY and Dvorak layouts, designed for efficient and ergonomic touch typing in English, released in 2006 by Shai Coleman.</dd>
                <dt><label onClick={() => { setLayoutType('dh'); scrollToEle('final-layout'); }}>
                    <input type="radio" name="layout" value="DH" />
                    Colemak DH
                </label></dt>
                <dd>Colemak DH introduces a minor modification to the Colemak keyboard layout, designed to make typing more comfortable, released in 2014 by SteveP. Use this mod if you dislike continually reaching into the centre columns for the D and H keys.</dd>
            </dl>
            <div id="final-layout">
                {!!(keyboardType && layoutType) && (
                    <>
                        <h2>And this is how your layout should look:</h2>
                        <p>
                            You chose:
                            {' '}
                            <strong>
                                {
                                    layoutType === 'vanilla'
                                        ? GENERATED_BLURB[layoutType]
                                        : GENERATED_BLURB.dh[keyboardType]
                                }
                            </strong>
                            {' '}
                            A great choice!
                        </p>
                        {generateLayout(keyboardType, layoutType)}
                        <p>
                            <a
                                href="#top"
                                onClick={() => {
                                    setKeyboardType(undefined);
                                    setLayoutType(undefined);
                                    
                                    document.querySelectorAll('input[type="radio"]').forEach((ele) => { ele.checked = false; });
                                }}
                            >
                                Start again
                            </a>
                        </p>
                        <h3>Legend</h3>
                        <p>To help you achieve the best performance, you should use these fingers for the coloured keys above. But after you’ve learnt the layout well, research if alternate-fingering is right for you!</p>
                        <ul className="legend">
                            <li><span className="key pinky" title="pinky finger"></span> Pinky finger</li>
                            <li><span className="key ring" title="ring finger"></span> Ring finger</li>
                            <li><span className="key middle" title="middle finger"></span> Middle finger</li>
                            <li><span className="key index" title="index finger"></span> Index finger</li>
                        </ul>          
                    </>
                )}
            </div>
        </>
    );
};

ReactDOM.render(<Component />, document.getElementById('output'));
              
            
!
999px

Console