<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5HGSQD2L" height="0" width="0" style="display:none;visibility:hidden" title="GTM"></iframe>

React setup

Install SWAN

Configuring the .npmrc file for your project

SWAN is hosted in a private npm repository, so to install the package, you need to ensure that your .npmrc file is configured.

Add an .npmrc file to the root of our project with the following content.

Share
Share

You need to configure the VP_ARTIFACTORY_TOKEN environment variable in your system. To retrieve the value, please log in to jfrog and configure your npm client by login into it.

Read more in detail at "Install NPM Packages from Vistaprint Artifactory"

Install the latest version of SWAN

  • Peer Dependency
    • react: >=17 <19 (Preferred version ^18.3.0)
    • react-dom: >=17 <19 (Preferred version ^18.3.0)
Share
Share

For Library Owners

The library only needs @vp/swan for dev dependency and should keep it as a peer dependency in their package.json.

You are not required to do the below setup for your library, but if you do have an example/sample application, you need to configure based on the type of sample application you have.

Project setup

Setup with popular frameworks like Create React App (CRA), Gatsby, and Next.js.

Getting Started With Gatsby < 4.19

Since previous versions of Gatsby don't come with Head API we will need to use Helmet.

  • SwanConfiguration configures the SWAN provider using react-helmet-async, since Gatsby doesn't come with any head management toolkit.
  • gatsby-ssr.js wrapRootElement wraps the SwanConfiguration for all the pages during SSR mode.
  • gatsby-browser.js wrapRootElement wraps the SwanConfiguration for all the pages in the browser.
  • gatsby-config.js: You need to add the gatsby plugin for react-helmet.
  • Layout gives an overall pattern for the page, along with skip links for accessibility support.
  • Install react-helmet-async and gatsby-plugin-react-helmet for this setup to work.
Share
Share
Share
Share
Share
Share

Getting Started With Gatsby >= 4.19

The latest version of gatsby comes with its own Head management toolkit.

In Summary, all the pages and templates should return a named component called Head which should modify everything in Head. This will receive the data and pageContext that the default component receives.

Additionally, to modify attributes on html or body tag, you need to use the appropriate methods inside onRenderBody (as shown below). Additionally, you could modify head within this as well which are common to all the pages.


Since this doesn't need helmet, you don't need to install helmet, or configure gatsby-config with react-helmet plugin.

Please refer to PageOrTemplate example on how to manage SEO

When rendering with SSR/SSG, your application should be wrapped in <SwanSSRProvider /> to avoid hydration issues.

Share
Share
Share
Share

Getting Started With NextJS

  • SwanConfiguration configures the SWAN provider using Head
  • _app.js wraps SwanConfiguration for every page.
  • Layout gives an overall pattern for the page, along with skip links for accessibility.
Share
Share
Share

NextJS App Router


NextJS's App Router introduces a framework for building applications and relies on experimental React features such as React Server Components (RSCs). The App Router uses a canary version of React and includes functionality not included in the latest production version, 18.3.0.

As of SWAN 3.0, all components are marked with 'use client' - meaning they will render on the server, but also hydrate on the client.

SWAN Utility Components and CSS Classes

Because SWAN components are treated as client components, they cannot be used inside of server components (except when passed through as children props).

Instead of rendering something like <P marginTop={3}>My Paragraph</P> the CSS utility classes can be used instead: <p className="swan-mt-3">My Paragraph</p>. This approach lacks type safety, so is best avoided, if possible

Getting Started With CRA or Parcel

We will use React helmet to manage everything on the client side itself.

Share
Share
Share

Getting Started With CRA with webpack

This approach tries to manage head during build time of SPAs.

  • We need react-helmet-async, craco, and a few webpack plugins to configure CRA.
  • SwanConfiguration configures the SWAN provider using react-helmet-async, since CRA doesn't come with any head management toolkit.
  • We recommend using craco to modify the webpack plugin, and to inject meta tags, font preload links, font face configuration, favicons, and stylesheets.
  • App gives an overall pattern for the page, along with skip links for accessibility.
  • Index shows how to wrap your app with SwanConfiguration .

Why are we using Webpack plugins?

CRA is a client-side only Single Page Application, and SwanProvider could only update the head once it is downloaded and executed. Also, once the head is updated, the browser will start loading fonts, stylesheets, etc.

Webpack plugins will allow us to inject those in the head during the build phase itself. Thus, when this goes to the browser, all the assets could be loaded before the React app is initialized -- and therefore when the content renders, there will be no Flash of Unstyled Content (FOUC).

Share
Share
Share
Share
Share
Share

react-helmet vs. react-helmet-async

react-helmet is a package from the NFL for managing HTML elements in the <head> of the page. It is no longer maintained and hasn't been updated in years. As a result, Gatsby and Next have introduced their own head management libraries.

If you are not using one of those frameworks and are still relying on react-helmet, you may see an error like Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code, especially in React 18. In that case, switch to react-helmet-async, which has the same API, but better supports modern version of React.

SwanProvider

Props summary:

  • swanTenant: Takes a valid tenant
  • swanLocale: Takes a valid locale
  • swanBaseUrl: This takes a baseUrl for the SWAN assets. Use this if you don't have swanTenant and swanLocale. If provided alongside the mentioned ones, this will have a higher priority. This falls back to our CDN. You could pass options via our Map like SWAN_BASE_URL_MAP.vistaprint.com for the .com domain.
  • pathType has two possible values: hashed | versioned exported via an enum SwanPathTypeEnum. Each asset is stored at two paths: one using the content hash, and one using the package version. It defaults to hashed, which is the recommended value. Not all the asset files change between different versions of SWAN, and so if they have the same content, they will also have the same hash across different versions of SWAN.
  • globalLinkComponent: Specify which component should it use when using the SwanLink component. Frameworks like gatsby and nextjs comes with their own link component and for CRA you might use link component from the routing library you are using.

What is swanBaseUrl?

To set the stage for this section, we'll start with a quick refresher on how the browser handles <link>/<script> tags. Feel free to skip the next paragraph if you're already familiar with optimizing load times by using same-domain requests!

Once your page's HTML is downloaded, the browser is going to discover a bunch of <link> and <script> tags that reference remote assets that need to be downloaded. If those secondary assets are served from a different domain than your HTML, then the browser will need to go through an additional connection process for each new domain. However, if those assets are served from the same domain as your HTML, then the browser can use its existing connection which saves time!

By default, SWAN will return URLs with the https://swan.prod.merch.vpsvc.com domain, but we've also made sure that our assets are available via each of our production domains (e.g. vistaprint.ie) on a proxy path /swan/. So, when building for production, we recommend that you specify the appropriate domain via the domain option in SwanProvider’s swanBaseUrl prop.

e.g. if you're building a page that will be accessed via vistaprint.es, you should specify swanBaseUrl={SWAN_BASE_URL_MAP.vistaprint.es}.

Note: Use this if you don't have swanTenant and swanLocale. SwanProvider can internally determine teh base URL if swanTenant and swanLocale are provided and fall backs to CDN. If swanBaseUrl is provided alognside these, it will have highe rpriority

It is common in single-page apps to use a routing library like React Router in order to handle client-side routing. Frameworks like Gatsby and Next make use of a routing library as well.

One thing that routing libraries have in common is that they ship their own Link components that you must use throughout your SPA rather than simply rendering <a> tags. This allows the routing library to circumvent the browser's normal anchor logic and enables the library to handle the linking (and even pre-fetching in some cases).

All SWAN components are configurable in such a way that you can easily tell them to render a custom component rather than the default tag that they usually render.

Swan, Gatsby, and React-Router all export a component with the name Link which is confusing. From here on, I'll refer to those as SwanLinkGatsbyLink, and ReactRouterLink for clarity.

e.g. you can tell a SwanLink to render a GatsbyLink rather than an <a> like this:

Share

But what if you want all SwanLink to use GatsbyLink by default? It would be tedious and error-prone to add the component prop to every instance of SwanLink.

That's where globalLinkComponent comes in.

Share

With globalLinkProvider configured, all SwanLinks underneath the SwanProvider will render a GatsbyLink by default! And don't worry, you can still override any individual SwanLink's component via the component prop.



SwanHead

SwanHead takes below props

  • swanBaseUrl (Required): It is optional and tries to read from SwanProvider when used as the child. For cases where SwanHead is used outside the provider like gatsby-ssr or next.js _document.js, pass the appropriate value. The default value is the Swan CDN URL
  • swanPathType (Optional): Defaults to SwanProvider's value if inside else hashed.
  • styleSheetKeys (Required): List of all the stylesheets that it needs to load. Swan Doesn't support auto-loading of styles. So pass all the values. It defaults to loading all the CSS.
  • fontNames (Optional): List of all the fonts you want to load. Note: if you set this, you will need to list all the fonts you want, not just the ones you want to add to the default font. So if you want to use both Graphik and Tiempos on your page, you would need to set <SwanHead fontNames={[SwanFontNameEnum.Graphik, SwanFontNameEnum.Tiempos]} ...>

When using Helmet, pass additional props:

  • renderWith={Helmet} defaults to using React.Fragment. Works for gatsby and nextjs Head.
  • renderStyleContentAsChildren since Helmet expects the style content as children as opposed to the props dangerouslySetInnerHTML

Page Meta Tag

The SWAN library simplifies the management of essential page meta tags as part of the SwanHead component, ensuring optimal performance and functionality for your web application.

With SWAN, you no longer need to manually include and configure these meta tags individually. The library takes care of the following meta tags for you within the SwanHead component:

Share

By leveraging the SWAN library's meta tag management capabilities, you can focus on developing your application without worrying about the intricate details of meta tag setup.


getRootClassNames

Swan is built to be interoperable with other design systems to allow incremental adoption. In order to achieve this, everything related to swan must be within the swan class.

Generally the root class names are applied to the body tag if you want swan to work on the entire page. When doing incremental adoption, you should apply this to the html element under which you want swan to work.

It takes a configuration object with below attributes:

  • standardMode?: boolean (default: false)
  • darkMode?: boolean (default: false)

The preview has been updated.


useBrowserClasses

This accepts an optional boolean parameter that will add the browser's name as a class name on the <head> tag. For instance, if you are using Firefox, you should see class swan-firefox on the <head> tag.

We account for the following browsers by analyzing the navigator.userAgent:

  • Safari
  • Firefox
  • IE
  • Edge (pre-Chromium, and Chromium-based)

The preview has been updated.

Testing

waitForStyles


When testing SWAN components, especially in a browser-based testing solution like Playwright or Cypress, you may need to wait for SWAN styles to be loaded before running your test assertions. We provide a testing utility called waitForStyles that does exactly what it's called - it returns a promise that resolves when the SWAN style keys are loaded. To use, put await waitForStyles() in your test.

Jest Setup


UI testing in jest relies on jsdom, a node-based implementation of browser standards. The ModalDialog component relies on the native dialog element, which jsdom does not yet support. This might cause unit tests to fail with an error like "dialogRef.current.showModal is not a function." You can mock the HTMLDialogElement API in your jest setup file with the following:

Share