@ithaka/pharos
v14.5.1
Published
Pharos web components for products and experiences
Downloads
2,655
Keywords
Readme
Pharos Web Components
- Installation
- Registering components
- Using web components
- Using Pharos components in React
- Styling components
- Using Pharos design tokens
- Typography and mixins
- Additional component styles
- Using Pharos form elements in forms
- Adoption Governance Model
Web Components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps.
Pharos provides a web component library for building products consistent with the JSTOR brand.
If you're using Vue, you can use these components in the same manner specified, without any additional steps!
Installation
$ npm install @ithaka/pharos
Registering components
- To allow multiple versions of Pharos to exist on a page, this package only exports component classes for you to register on the custom element registry in your application. To register components, you can use the
registerComponents
utility to define all the Pharos components your application uses, with a consistent scoping prefix:
import { PharosAlert, PharosButton, PharosIcon } from '@ithaka/pharos';
import registerComponents from '@ithaka/pharos/lib/utils/registerComponents';
registerComponents('homepage', [PharosAlert, PharosButton, PharosIcon]);
Note: When using module federation, you may only share Pharos successfully by using the registerComponents
utility. This avoids registering elements with the same underlying class instance, which would result in an error.
To manually register a component, import the classes you wish to use in your application's entrypoint and define the custom element with a tag name in the form of {app/bundle}-pharos-{component}
and a trivial subclass that extends the Pharos class wrapped in the PharosComponentMixin
:
import { PharosAlert } from '@ithaka/pharos';
import PharosComponentMixin from '@ithaka/pharos/lib/utils/mixins/pharos-component';
customElements.define('homepage-pharos-alert', class extends PharosComponentMixin(PharosAlert) {});
Note: If you register a name that already exists the browser will throw an error about the duplicate.
Internally, Pharos components that are composed of other Pharos components scope their registries to their shadow root to avoid duplicate registrations. Because the
Scoped Custom Element Registries
proposal is not yet finalized, you need to apply a polyfill to use our components.Every component sets a custom data attribute
data-pharos-component
on itself with its class name (such asPharosAlert
) to allow you to query any instance of that component regardless of its defined tag. Components also use this attribute to locate slotted Pharos children. Bundlers minify these class names by default for production builds. To ensure components work as expected, update your configurations like so:
Webpack (Terser):
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: /^Pharos/,
keep_fnames: /^Pharos/,
}
}),
],
}
Vite (ESBuild):
export default defineConfig({
esbuild: {
keepNames: true,
},
});
Using web components
After installing Pharos and registering the components, you can render them in any of your templates:
<pharos-tooltip>
<button>Hover here!</button>
<span slot="content">I am a tooltip</span>
</pharos-tooltip>
See the web component Storybook for details on component-specific syntax.
Using Pharos components in React
React is a JavaScript library used to build encapsulated components that manage their own state. React doesn't currently play perfectly with native web components, so if you're developing a React application you need to use the wrapper components provided in the lib/react-components/
directory of the package.
To use the React components, first register the components using the registerComponents
utility. Then, in your app's entry file, use the PharosContext
context provider to indicate the scoping prefix you registered them under:
import { PharosContext } from '@ithaka/pharos/lib/utils/PharosContext';
const context = { prefix: 'homepage' };
Then, render it in your JSX:
<PharosContext.Provider value={context}>...app code</PharosContext.Provider>
To use a component, first import it:
import { PharosTooltip } from '@ithaka/pharos/lib/react-components';
Then, render the component in your JSX:
<PharosTooltip content={'I am a tooltip'}>Hover here!</PharosTooltip>
See the React Storybook for details on component-specific syntax.
Styling components
Pharos components utilize CSS variables for their styling. To style components across your app, import the variables like so in your styles entrypoint:
/* index.css */
@import '@ithaka/pharos/lib/styles/variables.css';
/* More global styles */
Using Pharos design tokens
Components in Pharos are styled using design tokens, a tech agnostic way to store design decisions such as typography, color, and spacing so that Pharos can be shared across platforms. You can use these tokens to help style your own components and pages to ensure the brand is properly expressed to users. The token files are located in the lib/styles/
directory of the package.
To use the tokens as SASS variables, import them like so in the file where you want to use them:
/* example-page.scss */
@import '@ithaka/pharos/lib/styles/_variables';
/* More styling for the example page */
To use the tokens as ESM modules in your JavaScript, import them like so to ensure unused tokens are tree-shaken:
/* example-page.js */
import { PharosColorTextBase } from '@ithaka/pharos/lib/styles/variables';
Typography and mixins
Pharos uses Ivar
a serif primarily for headlines and GT America
a sans serif for body copy. The font-face stylesheet and base typography styles are located in the lib/styles/
directory of the package. Import them, along with the design tokens, in your app's styles entrypoint file:
/* index.scss */
@import '@ithaka/pharos/lib/styles/fonts.css';
@import '@ithaka/pharos/lib/styles/variables.css';
@import '@ithaka/pharos/lib/styles/typography';
/* More global styles and imports */
Pharos also provides SASS mixins which are reusable styles shared across multiple components. Import them like so in the file where you want to use them:
/* example-page.scss */
@use '@ithaka/pharos/lib/styles/pharos';
.some-text {
@include pharos.font-base;
}
The base typography styles and mixins utilize SASS modules which replaces @import
with @use
to make CSS, variables, mixins, and functions from another stylesheet accessible in the current stylesheet. If your project uses Webpack for bundling, you will need to make sure sass-loader
is set to use dart-sass
instead of node-sass
as Node Sass is deprecated and does not support SASS modules. If using sass-loader
>= 9.0.0 no change is required as sass
is set as the default. Otherwise, update your Webpack config as so:
/* webpack.config.js */
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
}
}
You can access all Pharos variables, mixins, and functions from a single pharos.scss
entrypoint file. Import it in the file where you want to use its modules:
/* example-page.scss */
@use '@ithaka/pharos/lib/styles/pharos';
.some-text {
@include pharos.font-base;
color: pharos.$pharos-color-text-20;
}
Additional component styles
Most components in Pharos benefit from the fully isolated styling provided by web components and CSS variables. However, some components provide slots you can populate with your own content. Content provided by application authors is rendered in the light DOM, and is not always stylable by web components.
You may need to import additional CSS files into your project's build for components whose slots expect nested content. These files are located in the lib/styles/
directory of the package. To use the CSS, import it in whichever bundle will be included on the same page as your component:
/* example-page.css */
@import '@ithaka/pharos/lib/styles/pharos-alert.css';
/* More styling for the example page */
Selectors in component stylesheets are scoped to the component's host element (<pharos-alert>
in the above example).
Components that have corresponding stylesheets are:
pharos-alert
pharos-footer
pharos-modal
Using Pharos form elements in forms
Pharos form elements listen to the formdata
event to add their values to the enclosing <form>
. Safari doesn't natively fire the formdata
event, so form authors need to fire a custom event in its stead.
Pharos provides a cross-browser createFormData
utility function for populating forms via a custom formdata
event. You should call createFormData
in your form's submit
event handler.
import createFormData from '@ithaka/pharos/lib/utils/createFormData.js';
const form = document.querySelector('form');
form.addEventListener('submit', (event) => createFormData(event.target));
If you submit your forms asynchronously, you can pass the result of createFormData
in your request:
import createFormData from '@ithaka/pharos/lib/utils/createFormData.js';
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = createFormData(event.target);
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://some-url.com');
xhr.send(formData);
});
Adoption Governance Model
Take a look at the adoption governance model for a quick overview of the adoption process.