Upgrade to Pro — share decks privately, control downloads, hide ads and more …

input, i ♥️ you, but you're bringing me down

input, i ♥️ you, but you're bringing me down

Browsers have had an <input> element since the dawn of time, and yet any time you talk to web developers about it, everyone complains about it. It's unpredictable. It's grumpy. It's got reaaaaally strong opinions about style, and it doesn't want to listen to yours. I'm going to tell you a story about how grew up to be the moody adult it is, and why it's maybe time we stood up to it.

Monica Dinculescu

June 16, 2016
Tweet

More Decks by Monica Dinculescu

Other Decks in Programming

Transcript

  1. but you’re bringing me down
    i you

    View full-size slide

  2. type=date not working properly
    empty input is invalid regardless of minlength
    type=number doesn’t work with pattern
    type=number can type eee without firing event
    weird caret offset with type=search
    typing moves cursor to the end

    View full-size slide

  3. 1993
    the early years

    View full-size slide


  4. 1995 checkbox
    text
    password
    radio
    image
    hidden
    submit
    reset
    file

    View full-size slide

  5. 1995

    checkbox
    text
    password
    radio
    image
    hidden
    submit
    reset
    file

    View full-size slide

  6. cool cool cool
    because input

    View full-size slide

  7. 1995
    1999
    bit slow, tbh
    -

    View full-size slide

  8. in which input does
    a lot of suffering

    View full-size slide

  9. An element satisfies its
    constraints
    if it is not suffering

    View full-size slide

  10. Suffering from being missing

    View full-size slide

  11. Suffering from being too short

    View full-size slide

  12. Suffering from being too long

    View full-size slide

  13. Suffering from a step mismatch

    View full-size slide

  14. cool cool cool
    because input

    View full-size slide


  15. 2011 week/month
    color
    date/time
    number
    range
    search
    email
    tel
    url

    View full-size slide


  16. 2016 week/month
    color
    date/time
    number
    range
    search
    email
    tel
    url

    View full-size slide


  17. 2011 week/month
    color
    date/time
    number
    range
    search
    email
    tel
    url

    View full-size slide

  18. but, as we know,
    CSS

    View full-size slide

  19. input[type=range] { … }
    // Webkit
    ::-webkit-slider-thumb { … }
    ::-webkit-slider-runnable-track { … }
    // FF
    ::-moz-range-thumb { … }
    ::-moz-range-track { … }
    // Never stop being different, IE <3
    ::-ms-thumb { … }
    ::-ms-track { … }
    ::-ms-fill-lower { … }
    ::-ms-fill-upper { … }

    View full-size slide

  20. input[type=range] { … }
    // Webkit
    ::-webkit-slider-thumb { … }
    ::-webkit-slider-runnable-track { … }
    // FF
    ::-moz-range-thumb { … }
    ::-moz-range-track { … }
    // Never stop being different, IE <3
    ::-ms-thumb { … }
    ::-ms-track { … }
    ::-ms-fill-lower { … }
    ::-ms-fill-upper { … }

    View full-size slide

  21. input[type=range] { … }
    // Webkit
    ::-webkit-slider-thumb { … }
    ::-webkit-slider-runnable-track { … }
    // FF
    ::-moz-range-thumb { … }
    ::-moz-range-track { … }
    // Never stop being different, IE <3
    ::-ms-thumb { … }
    ::-ms-track { … }
    ::-ms-fill-lower { … }
    ::-ms-fill-upper { … }

    View full-size slide

  22. input[type=range] { … }
    // Webkit
    ::-webkit-slider-thumb { … }
    ::-webkit-slider-runnable-track { … }
    // FF
    ::-moz-range-thumb { … }
    ::-moz-range-track { … }
    // Never stop being different, IE <3
    ::-ms-thumb { … }
    ::-ms-track { … }
    ::-ms-fill-lower { … }
    ::-ms-fill-upper { … }

    View full-size slide

  23. but as we know,

    JavaScript

    View full-size slide

  24. value = “1234”

    View full-size slide

  25. value = “1234”
    value = “”

    View full-size slide

  26. value = “1234”
    value = “”
    value = “”

    View full-size slide

  27. is an HTMLInputElement

    View full-size slide

  28. is an HTMLInputElement
    is an HTMLInputElement

    View full-size slide

  29. is an HTMLInputElement
    is an HTMLInputElement
    is an HTMLInputElement

    View full-size slide

  30. $(‘input[type=checkbox]’).checked

    View full-size slide

  31. $(‘input[type=checkbox]’).checked = false

    View full-size slide

  32. $(‘input[type=number]’)

    View full-size slide

  33. $(‘input[type=number]’).checked

    View full-size slide

  34. $(‘input[type=number]’).checked = true

    View full-size slide

  35. cool cool cool
    because input

    View full-size slide

  36. let’s do better

    View full-size slide

  37. a new hope
    2012

    View full-size slide

  38. web components
    2012

    View full-size slide

  39. we reusable things

    View full-size slide

  40. we encapsulation

    View full-size slide

  41. what do we need?

    View full-size slide

  42. what do we need?
    specs!

    View full-size slide

  43. encapsulation
    shadow DOM
    1

    View full-size slide

  44. reusability
    document.registerElement
    2

    View full-size slide

  45. but like, with code

    View full-size slide

  46. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);

    View full-size slide

  47. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);

    View full-size slide

  48. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);

    View full-size slide

  49. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);

    View full-size slide

  50. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    createdCallback() {
    this._value = null;
    }

    View full-size slide

  51. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    attachedCallback() {
    this._input = document.createElement('input');
    this._input = 'text';
    this._input = this._value;
    this.createShadowRoot().appendChild(this._input);
    this._input.addEventListener(‘keypress’, _restrict);
    this._input.addEventListener(‘input’, _onInput);
    }

    View full-size slide

  52. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    attachedCallback() {
    this._input = document.createElement('input');
    this._input = 'text';
    this._input = this._value;
    this.createShadowRoot().appendChild(this._input);
    this._input.addEventListener(‘keypress’, _restrict);
    this._input.addEventListener(‘input’, _onInput);
    }

    View full-size slide

  53. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    attachedCallback() {
    this._input = document.createElement('input');
    this._input = 'text';
    this._input = this._value;
    this.createShadowRoot().appendChild(this._input);
    this._input.addEventListener(‘keypress’, _restrict);
    this._input.addEventListener(‘input’, _onInput);
    }

    View full-size slide

  54. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    attachedCallback() {
    this._input = document.createElement('input');
    this._input = 'text';
    this._input = this._value;
    this.createShadowRoot().appendChild(this._input);
    this._input.addEventListener(‘keypress’, _restrict);
    this._input.addEventListener(‘input’, _onInput);
    }

    View full-size slide

  55. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    getValue() {
    return this._value;
    }

    View full-size slide

  56. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    setValue(v) {
    this._input.value = this._value = this._fix(v);
    }
    getValue() {
    return this._value;
    }

    View full-size slide

  57. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    _fix(value) {
    if (!value)
    return null;
    if (awfulRegex.test(value))
    return Number(value);
    return NaN;
    }

    View full-size slide

  58. class NumberInput extends HTMLElement {
    constructor() {…}
    createdCallback() {…}
    attachedCallback() {…}
    attributeChanged(which, oldV, newV) {}
    getValue() {…}
    setValue(v) {…}
    }
    document.registerElement(‘number-input’, NumberInput);
    attributeChangedCallback(which, oldV, newV) {
    if (which == 'value') {
    this._input.value = newV;
    }
    }

    View full-size slide

  59. when do we get it?
    now! sort of.

    View full-size slide

  60. when do we get it?
    ~~polyfills~~

    View full-size slide


  61. cool cool cool

    View full-size slide