Give names to behaviors not interactions
Tags: react
Published: 2019-01-03 12:48:17

---
title: Give names to behaviors not interactions
published: true
description: When it comes to React components, props are the API that developers consume.
tags: reactjs
---

When it comes to React components, props are the API that developers consume. A good API should be obvious, something the developer can guess. You want to make it easier for the developer to implement their feature and move on.

This is valid not just for developers creating component libraries, but also for developers building applications. Your team mates have to use the component API you create.

After consuming a bunch of articles + talks and doing an inventory of all the props we have in cosmos, I've come up a few guidelines.

Here's one of them:

> This post was originally posted on [my newsletter](https://sid.studio/newsletter) a few weeks ago, just saying.

We have this `Switch` component that accepts a prop, let's call it `something` for now.

A developer using our component can pass a function and we'll call it when the value changes.

<example>

![switch](https://sid.studio/blog/22/switch.png)

```js
<Switch something={fn} />
```

</example>

React gives us the freedom to call the prop whatever we want - `handler` / `clickHandler` / `onClick` / `onToggle` etc.

It has become sort of a popular convention to start your event handlers with an 'on' like `onClick`. This is because the HTML spec has a bunch of handlers that follow this convention already: `onkeydown`, `onchange`, `onclick`, etc.

Reusing an already existing convention is a great idea, your developers don't have to learn a new thing.

Okay, how about `onClick`?

```js
<Switch onClick={fn} />
```

I'm not a big fan of the `onClick` handler here because it assumes that a mouse click is the only way to interact with this component.

Users on a mobile device would `tap` the switch with their finger or `drag` it to the right. Users with visual impairment will use it with a screen reader and keyboard `keyPress`.

As a developer using this component, I don't want to think about how end users interact with this component. I just want to attach a function that is called when the value changes.

Let's use a interaction agnostic API:

```js
<Switch onToggle={fn} />
```

That makes sense, right? The switch `toggles` between it's two values.

Inside the component, you might want to proxy all possible interactions to the same function

```js
function Switch(props) {
  return (
    <div
      className="switch"
      /* click for mouse users */
      onClick={props.onToggle}
      onKeyDown={function(event) {
        /* if the enter key is hit, call event handler */
        if (event.key === 'Enter') props.onToggle(event)
      }}
      onDrag={function(event) {
        /* pseudo code */
        if (event.toElement === rightSide) props.onToggle(event)
      }}
    />
  )
}
```

We've internalised all the implementation detail to expose a nice API for our users (developers).

Now, let's talk about a component hopefully all of us can agree on - a text input.

<example>

![input](https://sid.studio/blog/22/input.png)

```js
<TextInput />
```

</example>

HTML has an [`onchange` attribute](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/onchange), the [React docs](https://reactjs.org/docs/forms.html) use `onChange` in their examples as well. There seems to be consensus around this.

```js
<TextInput onChange={fn} />
```

Easy peasy.

Now, let's put both these components together.

<example>

![together](https://sid.studio/blog/22/together.png)

```js
<TextInput onChange={fn} />
<Switch    onToggle={fn} />
```

</example>

Notice something odd?

Even though both the components need similar behavior, the prop is named differently. The props are perfect for their respective component, but when you look at all your components together, it's very inconsistent.

What this means for developer experience is that you always have to check what the prop is called before using it. Not ideal.

So, here's tip #2 for you: _Aim for consistent props across components._ The same behaviour should have the same prop across components.

This tip can also be phrased as _Aim for a minimal API surface area._ You should limit the amount of API a developer has to learn before they can start being productive.

That's a beautiful way to put it, all credit goes to [Sebastian Markbåge](https://twitter.com/sebmarkbage). (I've linked his talk at the end of this post)

The way to implement this tip is to pick one prop and use it across all your components. From the two props we have in our example `onChange` is also in the HTML spec, so some developers might have already heard of it.

<example>

![together](https://sid.studio/blog/22/together.png)

```js
<TextInput onChange={fn} />
<Switch    onChange={fn} />
<Select    onChange={fn} />
// etc.
```

</example>

The consistency across components and the resulting ease of learning your API outweighs having the perfect prop for an individual component.

---

Made it till here? Great! Here's some bonus content for you.

Let's talk about that function signature for a minute.

```js
<TextInput onChange={fn} />
```

An `onChange` event handler (`fn` in the above example), receives one argument - `event`.

It is triggered on each change to the input. You can get a bunch of useful information from this event

```js
function fn(event) {
  console.log(event.target) // input element
  console.log(event.target.value) // text inside the input element
  console.log(event.which) // which keyboard key was hit
}
```

I assume most developers would be interested in `event.target.value`, so that they can use it for some other task - setting in state, submitting a form, etc.

In the case of our custom `Switch` component, every action exposes a different `event`. This `event` will have different properties for a `click` event and a `drag` event. How we make sure the API is consistent?

We can manually set `event.target.value` for every event:

```js
function Switch(props) {
  /* custom handler */
  const fireHandler = event => {
    const newValue = !oldValue

    /* consistent property that devs can rely on: */
    event.target.value = newValue

    /* fire the handler from props */
    props.onChange(event)
  }

  return (
    <div
      className="switch"
      /* click for mouse users */
      onClick={fireHandler}
      onKeyDown={function(event) {
        if (event.key === 'Enter') fireHandler(event)
      }}
      onDrag={function(event) {
        if (event.toElement === rightSide) fireHandler(event)
      }}
    />
  )
}
```

Watch Sebastian's talk if you want to learn more about this concept: [Minimal API Surface Area](https://www.youtube.com/watch?v=4anAwXYqLG8s)

Hope this was helpful on your journey

Sid

> That was part of an ongoing series. If you enjoyed this, there's more where that came from 😉

[![newsletter](https://sid.studio/newsletter-snapshot.png?v=1)](https://sid.studio/newsletter)