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. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ 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

              
                <form action="" id="my-form" method="post">
    <div id="root"></div>
    <button>Submit</button>
</form>

<!--
    More details below :)
-->















<br><br>
<details>
    <summary>Findings</summary>
    <ul>
        <li>
            <span>There is no widely-supported way to have a user-friendly display date format while sending a programming-friendly date format without JavaScript.</span>
            <ul>
                <li>If <code>&lt;input type="date" /&gt;</code> is used and client-side JavaScript is disabled, then on supported browsers the value will be <code>"YYYY-MM-DD"</code>, and on unsuported browsers the value will be <code>"mm/dd/yyyy"</code>.</li>
            </ul>   
        </li>
        <li>
            <span>Since multiple resources say the user should always be given the option to type in the date, we have a few options:</span>
            <ol>
                <li>
                    <span>Always use <code>&lt;input type="text" /&gt;</code></span>
                    <ul>
                        <li>No built-in datepicker tools, would have to write our own with JavaScript ☹️.</li>
                        <li>The date format would be consistent regardless of the user's browser or whether or not they have client-side JavaScript enabled πŸ˜€.</li>
                    </ul>
                </li>
                                <li>
                    <span>Always use <code>&lt;input type="date" /&gt;</code></span> <ul>
                        <li>We get built-in datepicking tools on supported browsers without any JavaScript πŸ˜€.</li>
                        <li>If <code>&lt;input type="date" /&gt;</code> isn't supported on a specific browser, we could still use our own client-side JavaScript datepicker πŸ˜€.</li>
                        <li>If JavaScript isn't enabled, then the date format will change depending on if the browser supports it or not. We would have to be aware of that possibility and make it consistent on the server, which would be difficult ☹️.</li>
                    </ul>
                </li>
                <li>
                    <span>Use <code>&lt;input type="text" /&gt;</code>, but then check if JavaScript is enabled, and if so use <code>&lt;input type="date" /&gt;</code></span>
                    <ul>
                        <li>If a user doesn't have JavaScript enabled then they won't have any datepicker functionality, even if they could have with <code>&lt;input type="date" /&gt;</code> ☹️.</li>
                        <li>If <code>&lt;input type="date" /&gt;</code> isn't supported on a specific browser, we could still use our own client-side JavaScript datepicker πŸ˜€.</li>
                        <li>The date format would be consistent regardless of the user's browser or whether or not they have client-side JavaScript enabled πŸ˜€.</li>
                    </ul>
                </li>
            </ol>
        </li>
        <li>#3 is implemented in this Codepen.</li>
        <li>If we don't like the native datepicker at all, #1 would be our best option.</li>
    </ul>
</details>

<br><br>
<details>
    <summary>Codepen Shortcuts (easier to access on phones)</summary>
    <ul>
        <li>
            <h3>Bitly</h3>
            <a href="https://bit.ly/2B9sy2B">https://bit.ly/2B9sy2B</a>
        </li>
        <li>
            <h3>QR Code</h3>
            <img src="https://user-images.githubusercontent.com/11892481/49822204-76f56100-fd4a-11e8-96ee-050ebf4ce6ed.png" alt="QR Code" />
        </li>
</details>

<br><br>
<details>
    <summary>Reading Materials</summary>
    <ul>
        <li>
            <a href="https://www.nngroup.com/articles/date-input/">Date-Input Form Fields: UX Design Guidelines</a> β€” <cite>Nielsen Norman Group</cite></li>
        <li>
            <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date"><code>&lt;input type="date" /&gt;</code></a> β€” <cite>MDN</cite>
            <ul>
                <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#Handling_browser_support">Handling browser support</a></li>
            </ul>
        </li>
        <li>
            <a href="https://zachholman.com/talk/utc-is-enough-for-everyone-right">"UTC is Enough for Everyone, Right?"</a> β€” <cite>Zach Holman</cite>
            <ul>
                <li><a href="https://zachholman.com/talk/utc-is-enough-for-everyone-right#inputting-time">Inputting Time</a></li>
            </ul>
        </li>
        <li>
            <a href="https://www.smashingmagazine.com/2017/07/designing-perfect-date-time-picker/">Designing The Perfect Date And Time Picker</a> β€” <cite>Smashing Magazine</cite>
            <ul>
                <li><a href="https://www.smashingmagazine.com/2017/07/designing-perfect-date-time-picker/#perfect-date-and-time-picker-checklist">Perfect Date and Time Picker Checklist</a></li>
            </ul>
        </li>
        <li>
            <a href="http://eureka2.github.io/ab-datepicker/">Accessible Bootstrap Date Picker</a> — <cite>Jacques Archimède</cite>
        </li>
        <li>
            <a href="https://axesslab.com/accessible-datepickers/">Accessible datepickers</a> β€” <cite>Axess Lab</cite>
        </li>
        <li>
            <a href="https://caniuse.com/#feat=input-datetime">Date and time input types</a> β€” <cite>Can I Use...</cite>
        </li>
    </ul>
</details>
              
            
!

CSS

              
                summary {
    cursor: pointer;
    user-select: none;
}

li {
    margin: 10px 0;
}

.timepicker__header {
    display: block;
}

.timepicker__label {
    margin-right: 8px;
}

.timepicker__hint {
    color: DarkSlateGray;
}
              
            
!

JS

              
                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time#JavaScript
const _supportsTimeInput = () => {
    const timeInput = document.createElement('input')
    timeInput.type = 'time'
    return timeInput.type === 'time'
}

const _getMilitaryTime = isoFormat => {
    const [ hours, minutes ] = isoFormat.split(':')
    return `${hours}:${minutes}`
}

const _getAttr = ({ max, min, name, supportsTimeInput, value }) => {
    return supportsTimeInput 
            ? { 
                max,
                min,
                type: 'time',
            } 
            : { 
                name,
                type: 'text',
                value,
            }    
}
 
class TimePicker extends React.Component {
    state = {
        showButton: false,
        supportsTimeInput: false,
        value: '',
    }

    componentDidMount() {
        const supportsTimeInput = _supportsTimeInput()
        
        // This seems like you should only have to use
        // one value to keep track of the true/false state,
        // however this helps because both start (and can 
        // stay) false, but only one can ever be true
        this.setState({
            showButton: !supportsTimeInput,
            supportsTimeInput,
        })
    }

    handleOnInput = e => {
        const { value: targetValue } = e.target
        console.log(targetValue)
        this.setState(({ supportsTimeInput }) => ({
            // If the browser supports time inputs, then 
            // the value we get will be in 24-time, so 
            // we need to convert it to mm/dd/yyy
            value: !supportsTimeInput && targetValue ? _getMilitaryTime(targetValue) : targetValue,
        }))
    }
    
    handleButtonClick = () => {
        alert('A beautiful, accessible timepicker appears before your eyes!')
    }

    render() {
        const { buttonText, hint, inputId, label, labelId, max, min, name } = this.props
        const { showButton, supportsTimeInput, value } = this.state

        const attr = _getAttr({ max, min, name, supportsTimeInput, value })

        return (

            <label className="timepicker" htmlFor={inputId}>
                
                <header className="timepicker__header" id={labelId}>
                    <span className="timepicker__label">{label}</span>
                    <small className="timepicker__hint">{hint}</small>
                </header>
                
                <input 
                    aria-labelledby={labelId}
                    autoCapitalize="on" 
                    autoComplete="off" 
                    autoCorrect="off"
                    className="timepicker__input"
                    id={inputId}
                    maxLength="10" 
                    onInput={this.handleOnInput}
                    spellCheck="false" 
                    { ...attr }
                />

                {
                    // If the time input is supported, we still probably want 
                    // to submit the time value to the server-side in a consistent 
                    // format, so we'll use a hidden input to do so.
                }
                
                { supportsTimeInput && (
                    <input name={name} type="hidden" value={value} />
                )}
            </label>
        )
    }
}

TimePicker.defaultProps = {
    buttonText: 'πŸ“…',
    max: null,
    // This line defaults to the current day 
    // (may be useful) for preventing user 
    // from scheduling an event in the past
    min: new Date(Date.now()).toISOString().split('T')[0],
}

TimePicker.propTypes = {
    buttonText: PropTypes.string,
    hint: PropTypes.string.isRequired,
    inputId: PropTypes.string.isRequired,
    label: PropTypes.string.isRequired,
    labelId: PropTypes.string.isRequired,
    max: PropTypes.string,
    min: PropTypes.string,
    name: PropTypes.string.isRequired,
}

ReactDOM.render(
    <TimePicker 
        hint="mm/dd/yyyy"
        inputId="timepicker-input"
        label="Start Time"
        labelId="timepicker-label"
        name="start-time"
    />,
    document.getElementById('root')
)

const mockFormSubmit = e => {
    e.preventDefault()
    const inputs = Array.from(e.target.getElementsByTagName('input'))
    const formData = inputs.reduce((acc, input) =>  ({
        ...acc,
        ...input.name && input.value && { [input.name]: input.value },
    }), {})
    
    alert(JSON.stringify(formData))
}

document.getElementById('my-form').addEventListener('submit', mockFormSubmit)
              
            
!
999px

Console