Contextually-aware web components
The secret is CSS custom properties, a.k.a. “broadcast” variables, which are like a radio station sending out a signal. Other elements can choose to “tune in” or not.
Before we dig in, let’s back up a bit and cover the general idea of contextually-aware components. In PatternFly Elements web components, all layout components (i.e. card, band, tabs, etc.) can change their background colors, so they must communicate information about that change so that nested content can make necessary updates to retain readability. We call this “context” and the three values PatternFly Element components currently support are “light”, “dark”, and “saturated”.
For example, if you place a pfe-cta
(call-to-action) inside a pfe-card
with a teal background, the CTA component needs to be aware of this new context in order to render the type in a color which is readable on that background. The same is true of other HTML elements such as paragraphs, headings, and links.
How does context work?
- On a layout component, such as
pfe-card
, if you set thepfe-color
attribute to something likepfe-color="complement"
this causes a bright background color to be set on the layout, like teal.<pfe-card pfe-color="complement"></pfe-card>
- In those same layout components, when we set the styles for that background color, we should also set a
—-theme
variable like this:
- The JavaScript in the layout component “sees” that variable and in turn prints the on attribute on the card. The final result is:
<pfe-card pfe-color=”accent” on=”saturated”></pfe-card>
. Also note that the--theme
variable continues to cascade downwards, unless it’s overridden. This is why it’s important to update the--theme
variable any time the background color is updated. - The CSS style block in the shadow DOM of
pfe-card
comes with a set of variables which are associated with theon
attribute. This is where the “broadcast” variables come in. Remember, other HTML elements can choose to “tune in” (or use) these variables, or not.
- Any element in the light DOM of the
pfe-card
, like paragraphs, can pick up the broadcast variables because thepfe-card
component includes this property:color: var( — pfe-broadcasted — text,#333);
In order for links to be styled properly, a global stylesheet must have styles like thisa { color: var( — pfe-broadcasted — link, #06c);}
(this can be found in pfe-base.css). - Other components, like
pfe-cta
, nested inside the card will also inherit the—-theme
CSS variable (a.k.a. custom properties) because they also adhere to the standard cascade. Thepfe-cta
will “listen” for the value of—-theme
and apply its own on attribute automatically, which can then be used, as needed, to change its own colors.<pfe-cta on=”saturated”>
. Before & after:
Now if you are creating a new PFE component, you’ll want an easy way to set all this up. To do this with Sass functions, you can utilize the pfe-broadcasted
function, and then pass in the name of the variable such as link or text.
Notice that the result is first a local variable, then a global broadcast variable (if present), and finally a fallback hex color.
Side note, if you haven’t yet, be sure to check out our related blog post about why we use empty local variables as theming hooks.
If you are building a “container” component that can contain other components, like a band, card, or tab set, then you will need to provide the value of the broadcasted variables. You can easily do this with the pfe-set-broadcast-theme
mixin.
In this example, we are setting the background color of the pfe-tab-panel
to a dark background color, so we also want to change the value of the broadcast variables. Include the pfe-set-broadcast-theme
mixin, and in the first argument, pass in the context you need, either “light”, “dark”, or “saturated”, then the Sass mixin will return all the theme variables and fallback values you need.
That’s it! Contextual theming made easy! Kudos to @castastrophe for writing the awesome Sass mixins and functions that make all this much easier within PatternFly Elements.
If you have questions or feedback, we’d love to hear about it, either here on Medium or in the PatternFly Elements issue queue. Thanks for reading!