Skip to content

Remote: Embedded UIs

Jonathan Pierce edited this page Jun 8, 2022 · 5 revisions

Embedded UIs

Use NextCapitalComponent

While it is possible to use the Embedded* modules directly, we recommend using the NextCapitalComponent provided by the local client. This component correctly handles the full lifecycle of an embed, and should be the easiest way to embed content. All examples assume that this component will be used.

See the "Local Client" documentation for more information on this component.

Guidelines For Embedding

To provide the best embedded experience, please follow these guidelines.

Provide Full Width (and Fixed Height)

Most of our embedded UIs will assume:

  • That they have the full page width available to them
  • That they are rendering within a fixed-height container

The assumptions are important because:

  • mobile/tablet breakpoints are based on page width
  • our UIs assume sticky headers/footers with scrollable content in-between

We also recommend that your app has this CSS within it:

html, body {
  width: 100%;
  height: 100%;
}

body {
  margin: 0px;
}

This CSS is exceptionally common and likely already present in your application. It isn't totally required, NextCapital must just be given a box with the full remaining height of the page.

NOTE: Some embeds, especially those that are not full applications, may not require the full width or a fixed height. See the documentation for the individual embed for more.

Ensure All Parent Container Have a Defined Height

For our CSS to work properly, all elements between the container you are rendering the NextCapital Client into and <html/> should have a defined non-auto height (eg: height: 100% or height: 500px). If footers are not sticking to the bottom of the container, this is the likely culprit.

Avoid Double Scroll

As noted above, our embedded UIs expect a fixed-height container that can contain scrollable content. This means that if the parent container can also scroll, there will be a "double scrollbar". This provides a poor user experience.

We recommend rendering only a narrow header (and perhaps a footer), and letting the embed have the entire rest of the page. Keep in mind: our embedded application can have a footer customized within it.

Providing as much space as possible to the embed (without double-scrollbars) is the key to a great embedded user experience.

Hook Up to All Events

Many embeds provide callbacks for events on their options. For the best user experience, hook up to as much of these as possible. While some of these may be truly optional (see the docs for the specific embed), the app may fail to work properly if others are not provided.

Be sure to follow the documentation for the specific embed you are using.

Do Not Modify Embeds

While rendering embedded content within the DOM of the parent application technically allows you to modify our DOM and CSS, we ask that you please do not.

  • Do not override CSS for embedded content
  • Do not modify the DOM or render content within embedded DOM
  • Do not use z-index styles to cover our content (transient popups or menus are okay)

These hacks are not supported and can break without notice.

BaseEmbed

All embed classes are descended from a shared BaseEmbed base class. While this base class cannot be used directly, it does provide a few things:

  • static get isSingular(): A static getter that returns a boolean indicating whether or not there can be multiple independent embeds or not. When true, there will only be a single underlying instance of the embedded content that is re-used between renders, and only one embed should be displayed at once. Singular embeds are stateful between mounts/unmounts, while non-singular ones will lose state. See the docs for each embed to see if it is singular or not.
  • All embeds share the same pattern: they provide a set of options in their constructor (which last for the lifetime of the embed), and can also provide render-specific options for each render. Some embeds may also provide additional methods for two-way communications. If present, these will be documented with the specific embed.
  • Singular embeds tend to render as full-fledged applications, while non-singular ones tend to render as just a section (which also tend to have fewer restrictions on where to render them).
  • To encourage use of NextCapitalComponent, we'll leave the full interface of BaseEmbed undocumented.

EmbeddedPlanning

The EmbeddingPlanning embed displays a full end-to-end experience for workplace users, covering:

  • minimum required information
  • investor consent / enrollment
  • plan customization
  • contributions
  • enrolled user / unenrollment
  • doc vault
  • etc...

This is essentially the same experience that the deployed application has for workplace users. There are some minor differences. For example, a session timeout popups appears in our deployed app, but not the embedded version (we expect the wrapping app to handle this).

Singular?

Yes. Only one instance of this can/should exist at once, and this embed will maintain state between mounts.

Options

  • onExit (function) - optional: Callback called when the experience exits (either without enrolling or after enrolling). This may not ever happen in certain configurations of the application. The parent app should navigate away when this occurs.
    • When not embedded, the application typically would log out in these situations.
    • NOTE: If your iFrame integration depends on the REIDRECT postMessage even, you should use onExit instead.
  • onEnrolled (function) - required: Callback called when the user completes enrollment.
  • onEnrollmentStart (function) - optional: Callback called when the user starts the enrollment process. The primary purpose of this callback if for the parent application to disable navigation while the enrollment processes.
  • onUnenrolled (function) - required: Callback called when the user complete unenrollment.
  • onUnenrollmentStart (function) - optional: Callback called when the user starts the unenrollment process. The primary purpose of this callback if for the parent application to disable navigation while the unenrollment processes.
  • onError (function) - required: Callback called when the embed experiences a fatal error (either from React failing to render or the API). While the embed will also display an error message, the parent application can use this to display their own.
  • onModalPushed (function) - optional: Called whenever a modal is pushed onto history.
  • onModalPopped (function) - optional: Called whenever a modal is popped from history.
  • onPagePushed (function) - optional: Called whenever a page is pushed onto history. NOTE: Will occur immediately.
  • onPagePopped (function) - optional: Called whenever a page is popped from history.

Any optional callbacks that are not provided will simply be no-ops. The return value of all callbacks is ignored.

Want another callback? Let us know, and we can probably get it done.

Render Options

This embed currently does not respond to any render options.

Additional Methods

This embed currently does not provide any additional methods.

Example

import React from 'react';

import { NextCapitalComponent } from '@nextcapital/client';

import Page from '../components/Page';

const EmbeddedPlanningExample = () => (
  <Page>
    <NextCapitalComponent
      getEmbed={
        (client) => new client.EmbeddedPlanning({
          onExit: () => window.alert('exit callback called'),
          onEnrolled: () => window.alert('enrollment callback called'),
          onUnenrolled: () => window.alert('unenrollment callback called')
        })
      }
      loadingContent={ 'loading...' }
    />
  </Page>
);

export default EmbeddedPlanningExample;