Complexity of selectors in web development ft React

January 16, 2022

Selectors essentially let’s us specify which part of HTML that we are trying to target for example:

<div class="parent">
  <div class="child"></div>
</div>

In the above example in order to select the child which is below parent in JS we would have to do something like this:

document.querySelector(".parent .child");

In CSS :

.parent .child {
  background: papayawhip;
}

I have used CSS class names as means to select which is generally the way to select elements.

So, CSS class names and some rules around composing them allow one to pick and choose elements from HTML.

So far so good, problems start to creep in when the app grows.

The complexity increases for selecting elements.

There was a poll on Twitter by Max Stoiber :

Even though the above example is having a simple structure around 57% of 14k people answered it wrong. At scale, it can get out of hand.

The reason being the selectors tie the CSS and HTML in a many-to-many relationship. We can have many CSS classes applied on a single element and a single CSS class can target many elements.

It's not simple but it is easy.

So what does it mean in practice - Looking at HTML and CSS you cannot determine what you will get.

What you see, may not be what you get.

I am sure every one of us has run into issues where we expect the element to have certain styles only to be surprised. We rely on browser tools to determine which class over-wrote what we expected.

Contrast above with the below CSS-IN-JS solution using emotion:

<div
  css={`
    color: blue;
  `}
>
  Hello
</div>

Here it's as close as it can be — What you see is what you will get.

So moving away from selectors in CSS actually reduced a bunch of complexity for us.

Now let’s think of Javascript how do we get around selecting HTML elements this way?

The same complexity will transfer over to JS as well since we use CSS selectors to pick elements.

The answer turns out to be to put HTML-in-JS which is JSX!

Now the only selector you need to give in React is the entry/mount node and that’s it! The way you write JSX is how the HTML shows up.

What you see is what you get!

Now there is actually one other aspect of web development that relies on CSS selectors - unit testing.

To remove complexity from CSS selectors we moved CSS to JS.

To remove the complexity of CSS selectors from JS we moved HTML to JS.

Our unit tests are already in JS 😄 , so what we can we do to reduce/remove the complexity in this case?

Lets take this below HTML form snippet :

<form>
  <label>
    First Name:
    <input type="text" class="text-field" name="firstname" />
  </label>
  <label>
    Last Name:
    <input type="text" class="text-field" name="lastname" />
  </label>
</form>

Here if you had to pick the first field and then the second field and clearly they have both same classnames, how can we do it?

We can do something like this:

document.querySelectorAll("text-field")[0].value = "something";
document.querySelectorAll("text-field")[1].value = "something else";

There are some obvious problems with the above approach:

  1. If there are many elements with a "text-field" class name before the given HTML snippet it would break the test.

  2. If we reorder the fields our test will fail.

  3. If somebody changes the class name the test will fail.

The answer to this problems turns out is to look at the page and think in terms of how a user would find elements. In the above case it’s the label!

Plain and simple we go find text field with particular label text to select the element so we would need something like:

getByLabelText("firstname");
getByLabelText("lastname");

This is so much better! and not to mention lot more semantic very less likely to break even if we change classnames add more html etc etc!

But how do we get selectors like this? look no further Kent C. Dodds has us covered 😃 in his react-testing-library :

https://testing-library.com/

Thanks for reading!

Some references :

Emotion

https://kentcdodds.com/blog/why-i-never-use-shallow-rendering

https://reactjs.org/docs/introducing-jsx.html