@patternfly/pfelement

Base class for PatternFly Elements

Usage no npm install needed!

<script type="module">
  import patternflyPfelement from 'https://cdn.skypack.dev/@patternfly/pfelement';
</script>

README

PFElement Element

This is the base element that all other PFElements should extend. It handles setting up a shadow root and applies Shady CSS if it is needed.

To create a new PFElement, use npm run new from the root of the PFElements repo. After answering a few questions, a new element will be generated for you by generator-pfelement.

Here is an example of a new element and how it extends the base PFElement.

import PFElement from "../pfelement/dist/pfelement.js";

class MyElement extends PFElement {
  // The HTML tag name for this element.  This will be passed into `customElements.define()`.
  static get tag() {
    return "my-element";
  }

  // The path to the element's SCSS file.  It is compiled to CSS at build time.
  get styleUrl() {
    return "my-element.scss";
  }

  // The path to the element's template.  This used at build time.
  get templateUrl() {
    return "my-element.html";
  }

  constructor() {
    // The call to super is first and contains a reference to the class itself.
    // This allows the base class to see any of MyElement's static properties.
    super(MyElement);

    // any other work to do during the constructor goes here
  }

  // connectedCallback runs when the element is placed into the DOM.  Note that
  // in dynamic apps, this _can_ happen more than once, for instance if an
  // element is moved from one part of the DOM tree to another.
  connectedCallback() {
    // super's connectedCallback goes first
    super.connectedCallback();

    // any other work to do during connectedCallback goes here
  }
}

PFElement.create(MyElement);

Tooling / functions

The base class has a set of tools available for use inside all web components extending it.

Types

Define the type of your web component by extending the PfeTypes getter. A component can be classified as container, content, or combo. These are defined in more detail in the documentation.

  // Declare the type of this component
  static get PfeType() {
    return PFElement.PfeTypes.Container;
  }

Context

All components automatically observe and react to the attribute on which can equal 1 of 3 possible options:

  • light
  • dark
  • saturated

Context is automatically passed down from parent components to their children (often being defined by container elements and observed and acted upon by content components) without manual intervention by a developer. This is done through the on attribute. The on attribute should not be manually edited or added or manipulated by the JavaScript of a component.

Adding the context attribute to any component will break that inheritance and manually invoke your preferred context. This is a way to opt-out of the contexts provided by parent elements. Only add this attribute if you want to walk away from inherited context.

Random ID

Need to set a random ID on any part of your web component? Use the randomId getter:

  this.newId = this.randomId;

CSS Variables

You can query for or set the value of a CSS variable using the cssVariable function. It has 3 possible inputs:

  1. name: The name of the CSS variable you are querying for (you can omit the -- at the beginning).
  2. value: This input is optional. By passing in a value to the function, you are opting to set the variable name you provided equal to the value you have passed in.
  3. element: This defaults to the this context of the web component calling the function but you can pass in any element. This is useful if you want to attach a specific CSS Variable to a shadow element in your template for example.

Querying for a variable's value:

this.cssVariable("pfe-cta--Color");

Setting a value for a variable:

this.cssVariable("pfe-cta--Color", "#333");

Setting a value for a variable on a template element:

this.cssVariable("pfe-cta--Color", "#333", this.shadowRoot.querySelector(".pfe-cta--arrow"));

Querying for a slot(s)

There are 2 functions, hasSlot and getSlot which allow you to query for the existence of a slot in the light DOM. These are useful in the templates as a means of avoiding printing empty slots or wrappers.

  • hasSlot: Accepts the name of the slot you are querying for (does not work for default slots yet) and returns a NodeElement of that slot if it exists and null if it does not.

  • getSlot: Accepts the name of the slot you are querying for (does not work for default slots yet) and returns a NodeList of all elements assigned to that slot, if they exist, and null if they do not.

Context set and update

There are 2 functions for updating the context of a component. The first, setContext, will update the context of the component calling the function using the following logic:

  1. Check that element for the value of the --context variable, if it exists.
  2. If it does not exist, the component then checks for a context attribute.
  3. Finally, if neither has a value, the optional feedback input value is used.

If a value is defined at any point of this flow, an on attribute will be attached and assigned that value.

The context_update function will use much the same logic except it updates the context for the component calling the function and triggers an update for all of it's pfelement children.

Debug logging

Debug logging can be enabled by running localStorage.pfeLog = true in the console. This setting is sticky, so you can refresh the page and debug logging will stay enabled on that domain. To disable debug logging, run localStorage.removeItem("pfeLog"). You can also run PFElement.debugLog(true) to enable and PFElement.debugLog(false) to disable, however it's almost always easier to use localStorage directly because it can be tedious to get a reference to PFElement from the console.

Printing debug log messages can be done with this.log("This is my debug log message") within any element's method. This will produce a console log such as: [pfe-band]: This is my console message..

Emit event

This allows you to dispatch an event in a standardized way. The function accepts the name of the event and an object containing details about that event. That object supports the following configuration:

Event setting Default value
bubbles true
cancelable true
composed false
detail {}

Elements should contain an events object which lists all the event names:

static get events() {
  return {
    change: `${this.tag}:change`
  };
}

And then reference that object in the following way to invoke those events:

this.emitEvent(
  PfeAccordion.events.change, {
    detail: {
      expanded: !this.expanded
    }
  }
);

Test

npm run test

Build

npm run build

Demo

From the PFElements root directory, run:

npm start

Code style

PFElement (and all PFElements) use Prettier to auto-format JS and JSON. The style rules get applied when you commit a change. If you choose to, you can integrate your editor with Prettier to have the style rules applied on every save.