Adding CSS
With our basic Hello Enact! app built and running, we can start to expand it by adding some styling. The first stop is defining and managing CSS classes in React followed by exploring CSS modules.
CSS Classes in React
CSS classes are the primary tool for adding visual styling to applications. Classes are assigned
to components using the className
property.
<div className="customClass">Content</div>
… which renders into the DOM as the rather similar …
<div class="customClass">Content</div>
You might expect JSX to use
class
to mirror HTML but that isn’t possible since JSX is ultimately transpiled to JavaScript, in whichclass
is a reserved word. See DOM Elements for other instances where JSX deviates from HTML and the Document Object Model (DOM).
You might be tempted to use hyphenated class names (
custom-class
), but CSS Modules, which will soon be covered, recommends using camelCased naming for local class names (see Naming).
For simple applications, global class names are easy to use and understand. For more complex applications, you will likely want a way to organize your CSS to improve maintainability and reuse. There are several methodologies (e.g. Object-Oriented CSS (OOCSS), Block Element Modifier (BEM), and a host of others) and pre-processors (e.g. SASS, Stylus, LESS) that offer different solutions to this problem.
CSS Modules offers another option that works well with other tools and methodologies by focusing on a narrow concern — modularization. This is the method that the Enact team recommends.
Introducing CSS Modules
CSS Modules is a specification that allows authors to write CSS (or SASS or LESS or …) using short, meaningful class names without being concerned about naming conflicts that may arise when using multiple global stylesheets.
All classes defined in a CSS Module are local by default. In practice, that means that they are renamed at compile-time to a unique string. In order to use these generated class names, the CSS Module exports a map of authored names to generated names. For example, the following CSS Module:
.customClass {
background: red;
color: white;
}
would export an object similar to the following:
{
customClass: '_13LGdX8RMStbBE9w-t0gZ1'
}
It’s also possible to declare classes be global using the :global
pseudo-selector, which prevents
the name mangling and makes the class reusable across components using the authored name.
:global .customClass {
background: red;
color: white;
}
Would export:
{
customClass: 'customClass'
}
We discourage using global classes with CSS modules because it creates an implicit dependency between your component and the CSS source file containing the global class. Implicit dependencies are not tracked by the build tools and may be omitted if the resources explicitly depending upon them are no longer included.
Creating a LESS file
Let’s create a ./src/App/App.module.less
file for our fantastic styling.
The webpack config provided by
enact create
includes support for the LESS preprocessor, so we’ve used that file extension here, even though we’re only using standard CSS syntax.
.app {
font-size: 48px;
}
Using CSS Modules
From your component’s perspective, a CSS module is treated like any other module. You can import
it to make it a dependency of your component and to obtain a reference to the class name map.
By convention, we import a component’s stylesheet into the
css
variable. In addition to the consistency benefit, it also provides a minor efficiency boost we’ll see later.
Modify App.js
Let’s make two changes to our App module (./src/App/App.js
) to import CSS module and to apply the
.app
style to our root element.
import css from './App.module.less';
const App = function () {
return (
<div className={css.app}>
Hello Enact!
</div>
);
};
export default App;
export {App};
Expressions in JSX
You might have noticed that the JSX in the sample above deviates from standard HTML. Notably, the use of the curly brackets ({}) around our css
variable. We can’t use
the string, "app"
, because that would reference a global CSS class rather than the locally-scoped
class name from our CSS module. Instead, we’re using a JSX expression which allows us to embed any
valid JavaScript expression within our JSX markup. The following will evaluate the expression,
css.app
, and pass the result as the value of the className
property for the <div>
.
<div className={css.app}>
JSX expressions can be used for property values or entire elements but not component names or property names.
Valid
<div className={a ? b : c} /> // ✅ property value {a ? <span>A</span> : <span>!A</span>} // ✅ entire child of <div> </div>
Invalid
<{a ? 'div' : 'span'}> // ❌ component name <span {a ? b : c}="value" /> // ❌ property name <span {a ? b="value" : c="value"} // ❌ entire property
Conclusion
In this part we’ve explored applying CSS classes to React components, importing locally-scoped classes from a CSS module, and using expressions in JSX to add dynamic properties and elements to our JSX.
In the next part, we’ll introduce kind()
, which adds some
syntactic sugar around creating Stateless Components.
Next: Introducing kind()