           return unless node.checked
           setValue(context, keypath, node.value)
         else
-          setValue(context, keypath, node[valueAttribute])
+          setValue(context, keypath, node[valueProp])
 
       keypath = keypathForKey(node, definition)
-      twoWayBinding = valueAttribute != 'textContent' && node.type != 'hidden'
+      twoWayBinding = valueProp != 'textContent' && node.type != 'hidden'
 
       if keypath[0] == '$root'
         context = rootContext


    indexes

  setupAttributeBinding = (attributeName, bindingName) ->
    booleanAttribute = attributeName in ['checked', 'indeterminate', 'disabled', 'readOnly']

    Twine.bindingTypes["bind-#{bindingName}"] = (node, context, definition) ->
      fn = wrapFunctionString(definition, '$context,$root,$arrayPointers', node)
      lastValue = undefined
      return refresh: ->
        newValue = fn.call(node, context, rootContext, arrayPointersForNode(node, context))
        newValue = !!newValue if booleanAttribute
        return if newValue == lastValue
        node[attributeName] = lastValue = newValue

        fireCustomChangeEvent(node) if attributeName == 'checked'

  for attribute in ['placeholder', 'checked', 'indeterminate', 'disabled', 'href', 'title', 'readOnly', 'src']
    setupAttributeBinding(attribute, attribute)

  setupAttributeBinding('innerHTML', 'unsafe-html')

  preventDefaultForEvent = (event) ->
    (event.type == 'submit' || event.currentTarget.nodeName.toLowerCase() == 'a') &&


      if twoWayBinding
        changeHandler = ->
          return if getValue(context, keypath) == this[valueProp]
          refreshContext()
          Twine.refreshImmediately()
        $(node).on 'input keyup change', changeHandler
