Including Components ==================== Up to this point we have all the functionality we need in a single file, but in practice we will of course want to share functionality, similar to how we used components in Ember. We will look at doing this by implementing our standard ARIA-conformant menu. First create a new directory ``src/js/components`` and into that add the following ``aria-menu.jsx``: .. code-block:: jsx import React from "react"; function AriaMenu(props) { const keyDown = (ev) => { if (ev.keyCode === 39) { let nextElement = ev.target.parentElement.nextElementSibling; while (nextElement && (nextElement.getAttribute('role') === 'separator' || nextElement.querySelector('*[role="menuitem"]').getAttribute('aria-disabled') === 'true')) { nextElement = nextElement.nextElementSibling; } if (nextElement) { nextElement.querySelector('*[role="menuitem"]').focus(); } } else if (ev.keyCode === 37) { let previousElement = ev.target.parentElement.previousElementSibling; while (previousElement && (previousElement.getAttribute('role') === 'separator' || previousElement.querySelector('*[role="menuitem"]').getAttribute('aria-disabled') === 'true')) { previousElement = previousElement.previousElementSibling; } if (previousElement) { previousElement.querySelector('*[role="menuitem"]').focus(); } } } return ( ) } export default AriaMenu; The code demonstrates a few features that we will want to discuss. In our previous component we only used ``useState`` to store the state to output, but if you look at the code above, you will see that it also uses ``props``. The distinction is that ``props`` (properties) are those state values that are set on the component, when the component is called from somewhere else in our application. In the code above, there are two properties ``props.class`` to set an optional class name and ``props.label`` to set the ARIA label. Additionally there is ``props.children``, which gives access to any nested code, basically doing the same as ``{{yield}}`` in an Ember component. With our ARIA menu implemented, we can now use this in our main application. Update the ``athena.jsx`` to use the new component: .. code-block:: jsx import React from 'react'; import ReactDOM from 'react-dom'; import AriaMenu from './components/aria-menu.jsx'; import '../styles/app.scss'; function Athena() { ... return (
... } As you can see, to include a nested component, we simply provide the name of the component formatted as an HTML tag. Any attributes we specify on that tag are then available in the component via the ``props``. That is why here we use the ``class`` and ``label`` properties to pass those values into the component. Using this inclusion pattern, we can then create arbitrarily large applications. In particular through the use of the routing components that we will use in the next tutorial, we can create different application states.