Accessibility

I'm not going to beat around the bush. It's a lot of work to make a web application fully accessible to all users. However failure to do so can lead to an extremely poor user experience for a segment of your users that are already at a disadvantage. Additionally, you could find yourself in the middle of a lawsuit if you don't make your web application accessible. So this is an extremely important subject that deserves more of your attention than a single exercise in a web app fundamentals workshop.

The web

The web platform has been meticulously designed to maximize accessibility for a diverse range of users. This includes addressing the needs of those with visual, auditory, motor, and cognitive impairments. A multitude of features have been implemented, such as keyboard navigation, screen reader compatibility, and voice command support.
Moreover, the platform offers extensive customization options, enabling users to tailor the appearance, text size, contrast, color, font, layout, and animation of a web page to their preferences.
Your job is to make it so the browser can employ these technologies to provide a great experience for all users. So while many accessibility concerns involve design and word choice, in your role as a web developer, a lot of your time will be spent ensuring your forms, links, and other interactive elements are properly labeled and structured.
One example of this is properly labeling your form elements so the browser knows which labels are associated to which form elements. This is important because screen readers will read out the label when the user focuses on the form element. If the label is not properly associated, you don't have any guarantees. There are a few ways to associate a label and a form element. A common way to do this is through the for and id attributes.
<form>
	<label for="name">Name</label>
	<input id="name" type="text" />
</form>
In React, the for attribute is not allowed as a prop, so you use htmlFor instead.
The web platform has many good built-in features for accessible elements, however, in some cases, you will need to use props prefixed as aria-. ARIA is an acronym for "Accessible Rich Internet Applications". It is a set of attributes that define ways to make web content and web applications more accessible to people with disabilities. You can find the ARIA specification on the w3.org website.
It's often said that the first rule of ARIA is "don't use ARIA". This is because ARIA is a tool of last resort. It is meant to be used when the browser and HTML alone are not enough to make your web application accessible.
One common example of this is error messages. The web doesn't have a built-in mechanism for associating error messages to the fields they're reporting on, so you need to use ARIA to do this.
<form>
	<label for="name">Name</label>
	<input
		id="name"
		type="text"
		aria-invalid="true"
		aria-describedby="name-error"
	/>
	<div id="name-error">Name is required</div>
</form>
There is a disappointing gap in the support various screen readers have for ARIA and other accessibility features. This is why it's important to test your web application with a screen reader on various platforms. You can use the NVDA screen reader on Windows, or the VoiceOver screen reader on Mac.
Another important aspect you'll have to work with a lot as a web dev is managing keyboard focus. For example, when the user navigates to a page, your application should automatically focus them to the first relevant focusable element on the page. Or, if the user submits a form and there are errors, your application should auto-focus to the first field with an error message.
One thing that can help a lot is using libraries that abstract away the complexities of accessibility for common components you need. In the Epic Stack for example, we're using a set of React components from Radix UI.

In Remix

Remix has some features that support you in making your application accessible. For example, Remix will automatically manage scrolling for you as the user navigates around your application, and if there's a situation where you don't want to restore scrolling, you have a lot of power to control this on a per-link or per-page basis. Learn more from this Remix Single YouTube video about Scroll Restoration.
Also, Remix's support for React enables you to use libraries (like Radix UI) which do a great job of making common components accessible.
Additionally, nested routes can help with maintaining keyboard focus in many instances. It is possible that in the future, Remix will add even better support for this.
Because we're dealing with both "reusable components" and "non-reusable" IDs, sometimes it can be handy to generate IDs. In React to do this in a way that is "safe" for a server render, you'll likely need to use the useId hook.