Photo by Elizaveta Dushechkina on Unsplash
React Native text input styled using just Tailwind - scaling up for accessibility
Creating nice styled text inputs in React Native is now easier than ever thanks to Tailwind, meaning we don't need to turn to large UI component libraries like Material any more. However, when ditching the libraries we must now consider all the accessibility features ourselves. Remembering to label everything is the bare minimum, what about if a user has their phone's font scaled up? Can our styles cope with large fonts?
I wanted to accurately create these inputs designed by Pixelz Studio
I knew I wanted to use Tailwind for the project, but these inputs were so similar to the Material UI's inputs that there was a temptation to use Material instead. Using Material brings a lot of UI elements with good customisation options. However, at some point there will always be something you have to fight with to customise. It is also not quite s good with react native as it is on the web in my opinion. I decided to give it a go with just Tailwind, and see if I could create something close to the designs that would be reusable and pass accessibility checks - including scaling up with the phone's font size setting
Here is a screenshot of my version, and you can test the finished example on Snack
Aim
Create text inputs with the styling of the inputs using just Tailwind. Features to include:
Label in the border on focus
Border and label should change colour with validation
Input should be easily reusable
Icons on left and right sides of input
Must pass accessibility checks:
Label read by screen readers
Screen readers should know what type of input it is
Should be able to scale font size via the phone's settings without affecting styling
Styling the label
The design includes a label which appears in the top border of the input once the input is focused. I wanted to attempt this feature using Tailwind. My first attempt used a hard-coded value for the translate-Y to move the text into the top of the input. This looked ok at normal font size, but of course, once the accessibility font scaling was turned up, the translation was no longer correct and it was not in position any more. A more dynamic solution was needed if this was to work with different font sizes.
Adding an `onLayout' function to store the height of the input allows us to translate the label's position dynamically:
const measureInput = (e: LayoutChangeEvent) => {
const height = e.nativeEvent.layout.height;
if (inputHeight !== height) {
setInputHeight(e.nativeEvent.layout.height); // Stored in state
}
};
const translateValue = inputHeight / 2;
return (
<>
{focused ? (
<View
style={[
tw`bg-white p-1 ml-3 z-1 absolute`,
{transform: [{translateY: -translateValue}]},
]}
> ...
```
To test with the accessibility font scaling on IPhone, go to Settings->Accessibility->display & text sizes:
This is how it looks with the font scaled up now:
Limitations
The validation here is very basic - far too basic for any real-world scenario. React Hook Forms can provide good validation, but custom validation would probably still be needed. I'm not very happy with how the validation errors are displayed - I think having a message under each field is not the best practice for accessibility. If a user has multiple fields that are invalid and is using a screen reader, they have to go through the form to see the errors one by one. A better approach would be to have one alert which lists the errors and provides a link to each error. Unfortunately, this does not appear in many designs for mobile that I have seen, and is perhaps an area we need to improve by working with designers to consider this more.
Resources
Design by Pixelz Studio