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 Slide

  2. @notwaldorf

    View Slide

  3. emojineer

    View Slide

  4. View Slide

  5. View Slide

  6. 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 Slide

  7. story time

    View Slide

  8. 1993
    the early years

    View Slide

  9. 1993

    View Slide

  10. 1995
    html2

    View Slide

  11. 1995

    View Slide


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

    View Slide

  13. 1995

    checkbox
    text
    password
    radio
    image
    hidden
    submit
    reset
    file

    View Slide

  14. View Slide

  15. (710, 303)

    View Slide


  16. View Slide


  17. View Slide

  18. View Slide

  19. View Slide

  20. View Slide


  21. View Slide

  22. View Slide

  23. View Slide

  24. View Slide

  25. View Slide

  26. cool cool cool
    because input

    View Slide

  27. 1995
    1999
    bit slow, tbh
    -

    View Slide

  28. in which input does
    a lot of suffering

    View Slide

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

    View Slide

  30. Suffering from being missing

    View Slide

  31. Suffering from being too short

    View Slide

  32. Suffering from being too long

    View Slide

  33. Suffering from a step mismatch

    View Slide

  34. Suffering.

    View Slide

  35. html4
    1999

    View Slide


  36. 1999

    View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. cool cool cool
    because input

    View Slide

  41. html5
    2011

    View Slide


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

    View Slide


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

    View Slide


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

    View Slide

  45. but, as we know,
    CSS

    View Slide

  46. View Slide

  47. 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 Slide

  48. 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 Slide

  49. 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 Slide

  50. 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 Slide

  51. View Slide

  52. View Slide

  53. but as we know,

    JavaScript

    View Slide


  54. View Slide

  55. value = “1234”

    View Slide

  56. value = “1234”
    value = “”

    View Slide

  57. value = “1234”
    value = “”
    value = “”

    View Slide

  58. wait for it

    View Slide

  59. is an HTMLInputElement

    View Slide

  60. is an HTMLInputElement
    is an HTMLInputElement

    View Slide

  61. is an HTMLInputElement
    is an HTMLInputElement
    is an HTMLInputElement

    View Slide

  62. View Slide

  63. View Slide

  64. View Slide


  65. View Slide


  66. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  72. View Slide

  73. View Slide

  74. cool cool cool
    because input

    View Slide

  75. let’s do better

    View Slide




  76. View Slide




  77. View Slide

  78. a new hope
    2012

    View Slide

  79. web components
    2012

    View Slide

  80. we reusable things

    View Slide

  81. we encapsulation

    View Slide

  82. View Slide

  83. View Slide

  84. how?

    View Slide









  85. View Slide









  86. View Slide









  87. View Slide

  88. what do we need?

    View Slide

  89. what do we need?
    specs!

    View Slide

  90. encapsulation
    shadow DOM
    1

    View Slide

  91. reusability
    document.registerElement
    2

    View Slide

  92. imports

    3

    View Slide

  93. but like, with code

    View Slide









  94. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  100. 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 Slide

  101. 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 Slide

  102. 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 Slide

  103. 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 Slide

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

    View Slide

  105. 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 Slide

  106. 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 Slide

  107. 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 Slide

  108. View Slide

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

    View Slide

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

    View Slide


  111. cool cool cool

    View Slide




  112. View Slide

  113. @notwaldorf

    View Slide