DEV Community

Cover image for Avoid Over-Propping with Accessible Components in React
Antonio Moruno Gracia
Antonio Moruno Gracia

Posted on

Avoid Over-Propping with Accessible Components in React

One of React's basics are props. They are used to pass data from a parent component to its child components. While they are a great way to handle flow of data, sometimes we tend to overuse them, leading to increasing code complexity and reduced readability. It may make the component harder to maintain, understand and reuse.

In this short article I'd like to propose one way to handle this problem, taking advantage of the ARIA Attributes.


❌ The problem

Sometimes we need to pass some props to our components for styling purposes. In this example, we need to create a Radio Button, which changes its border color depending of whether it's checked or not (in this case we're using styled-components).

type ComponentProps = {
  $checked: boolean
}

const Component = styled.input<ComponentProps>`
  // Some styles...

  ${({ $checked }) =>
    $checked
      ? css`
          border-color: 1px solid blue;
        `
      : css`
          border-color: 1px solid grey;
        `
  }
`

// Some code

return 
  <>
    <Component
      $checked={!!value}
      checked={!!value}
      id="component"
      type="radio"
    />
    <label for="component">Radio input</label>
  </>
Enter fullscreen mode Exit fullscreen mode

Since we already have the checked prop (html input has it natively), we'd have to create another prop if we wanted to apply some styles depending on it: $checked. We also need to type our component so Typescript knows that it has this new prop.

This technique adds a lot of unnecessary code and, moreover, it isn't accessible at all. Let's fix that.

✅ The solution

There are certain situations where we can avoid creating these props by ourselves. Instead, we can accomplish the same behaviour with ARIA Attributes.

const Component = styled.input`
  // Some styles...
  border-color: 1px solid grey;

  &[aria-checked='true'] {
    border-color: 1px solid blue;
  }
`

// Some code

return 
  <>
    <Component
      aria-checked={!!value}
      checked={!!value}
      id="component"
      type="radio"
    />
    <label for="component">Radio input</label>
  </>
Enter fullscreen mode Exit fullscreen mode

Notice that we're using the aria-checked attribute here. Not only we're avoiding creating unnecessary props, but also our application is much more accessible, keeping also the behaviour as close to native as possible.

Another examples where this approach might be useful:

  • aria-expanded for a dropdown component.
  • aria-disabled when we want to disable operations over a certain element.
  • aria-selected for an element selected in a tablist.
  • etc.

Take into account that, as said before, this only applies for certain situations. Some ARIA Attributes might not provide the intented utility. You must be careful and responsible, taking accessibility seriously. Use this approach wisely.

The main point of this article is to state that, most of the times, is better to remain as close to native as possible, rather than creating unnecessary code.

I hope you liked it!

Top comments (1)

Collapse
 
mattlewandowski93 profile image
Matt Lewandowski

Thanks for the tip. I always forget to utilize aria attributes for things like this.