Skip to main content

Problems with the change event on a color input in React

· 3 min read
Simon Porritt
VisuallyJs Development

Way back in the day, HTML offered a very limited set of components for capturing input from a user. Over the years this has changed, with new controls being introduced and finding widespread support across the various browsers. One of these new-ish input types (new-ish if you've been writing webapps for 20 years or so, anyway) is the color input:

#442288

You can click that color bar and you'll get a popup from which you can select a new color. When you change the color, the span next to it will update to tell you what the current color is.

Available events

According to MDN there are a couple of events you can hook into:

  • input input is fired on the input element every time the color changes
  • change The change event is fired when the user dismisses the color picker

In React, you'd use onInput or onChange to bind to these events.

onInput

For some usage scenarios, like if we want to immediately respond to the change in color as the user is using the color picker, it seems the input event would be a good choice. We can bind to that via React's onInput attribute:

export function ColorExample1() {
const [color, setColor] = useState("#442288")

return <div>
<input type="color" value={color} onInput={(e) => setColor(e.target.value)}/>
<span style={{color:color}}>{color}</span>
</div>
}

This is the code we're using in the example above.

onChange

But what if we only want to take action when the user has made their final choice, and dismissed the picker? Then it seems the change event would be a good choice. We can bind to that via React's onChange attribute:

export function ColorExample2() {
const [color, setColor] = useState("#442288")

return <div>
<input type="color" value={color} onChange={(e) => setColor(e.target.value)}/>
<span style={{color:color}}>{color}</span>
</div>
}

What we're expecting to see here is the the label to the right of the color picker will change after the user has dismissed the color picker. Try it:

#442288

But what do we actually see? The color changes immediately - the same behaviour as if we had used onInput. This is not the behaviour we wanted or expected.

Binding to the change event

In order to get the behaviour we want, we have to bind to the change event using the bare DOM approach:

export function ColorExample3() {

const input = useRef(null)
const init = useRef(false)
const [color, setColor] = useState("#442288")

useEffect(() => {
if(!init.current) {
init.current = true
input.current.addEventListener("change", (e) => {
setColor(e.target.value)
})
}
})

return <div>
<input type="color" defaultValue={color} ref={input}/>
<span style={{color: color}}>{color}</span>
</div>

}

Try opening the color picker here and selecting a few colors - you'll see the color picker update, but the label to the right of the picker will not be updated until you close the picker:

#442288

Summary

React has a very powerful event binding mechanism, but in this particular case it doesn't behave correctly. Fortunately you can always fall back to the DOM. The DOM will (almost) never let you down.



Try VisuallyJs

VisuallyJs offers an extensive list of starter apps, diagrams, charts and dashboards to quick start your development, in React, Angular, Vue, Svelte and Typescript/Javascript.

When you've reached the limits with ReactFlow, VisuallyJs has what you need
Call Flow
Use VisuallyJs to build a visual Call Flow editor
VisuallyJs - industry standard diagramming and rich visual UI Javascript and Typescript library
AI Agent Builder
Use VisuallyJs to create an advanced AI agent builder
When you've reached the limits with ngDiagram, VisuallyJs has what you need
Chatbot
Use VisuallyJs to build a Chatbot editor, with actions, messages, input and choices
VisuallyJs - callflow builders, sankey charts, database schemas, ERD diagrams and more
Flowchart
Fully featured flowchart builder including support for custom shapes, edge routing to avoid vertices, shape resize/rotate, SVG/PNG/JPG export and more
When you've reached the limits with ngDiagram, VisuallyJs has what you need
BPMN
BPMN editor for modelling the steps of a business process. Pools, lanes, and a full set of task, event and gateway types
When you've reached the limits with ReactFlow, VisuallyJs has what you need
ERD
ERD editor for modelling the steps of a business process
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
Gantt
Interactive Gantt chart featuring tasks, task groups and milestones
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
Kanban
Fully featured Kanban board. Drag items between columns and use the inspector to update items and columns
When you've reached the limits with SvelteFlow, VisuallyJs has what you need
Database Schema
Database Schema builder with support for tables, views, multiple columns types, and column relationships
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
Org Chart
Uses the classic org chart layout and provides an inspector from which the user can navigate around
VisuallyJs - industry standard diagramming and rich visual UI Javascript and Typescript library
Circuit Diagram
Fully featured starter app containing a circuit diagram builder
VisuallyJs - callflow builders, sankey charts, database schemas, ERD diagrams and more
Scada/HMI
Professional and modern Scada/HMI application with fluid, heating/cooling & instrumentation shapes, adhering to the HMI ISA-101 Design Standard
VisuallyJs - JavaScript and Typescript diagramming library that fuels exceptional UIs
Mindmap
The mindmap builder highlights several advanced features, such as custom layouts, parsers and exporters
VisuallyJs - fully featured alternative to ReactFlow and ngDiagram
Neighbourhood Views
Demonstrates how to include multiple views of a dataset on one page
VisuallyJs - JavaScript and Typescript diagramming library that fuels exceptional UIs
Logic Gates
Fully featured starter app containing a logic gates diagram builder
VisuallyJs - JavaScript and Typescript diagramming library that fuels exceptional UIs
Template
Basic starter app demonstrating how to setup VisuallyJs and its main features
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
Area & Line charts
Use VisuallyJs to create area and line charts
When you've reached the limits with SvelteFlow, VisuallyJs has what you need
Bar & Column charts
Multiple series, stacked, grouped, pivoted, and much more
When you've reached the limits with SvelteFlow, VisuallyJs has what you need
Scatter & Bubble charts
Circle, rectangle, triangle or custom markers, multiple series, fully customizable
VisuallyJs - build diagrams and rich visual UIs fast
Sankey chart
Use VisuallyJs to create a professional Sankey chart, with support for pivoting
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
Supply Chain Analyzer
Dashboard for managing and analyzing supply chains
VisuallyJs - build diagrams and rich visual UIs fast
Network Infrastructure
Combine a network management diagram with charts showing projected cost and resource usage
When you've reached the limits with SvelteFlow, VisuallyJs has what you need
Scrolling Lists
Use the ListManager plugin to manage scrolling lists: as elements are scrolled out of the view, their edges are moved to the list container
VisuallyJs - flowcharts, AI Agent builders, chatbots, bar charts, decision trees, mindmaps, org charts and more
FIFA World Cup
A visualizer for the FIFA World cup - group stages, team journeys and a tournament view.
When you've reached the limits with ngDiagram, VisuallyJs has what you need
Fault Tree Analysis
Combines a fault tree analysis diagram with charts showing risk and list of cut sets