Nocturnal Pumpkin Maelstrom

    @kentico/kontent-smart-link
    TypeScript icon, indicating that this package has built-in type declarations

    2.1.0 • Public • Published

    Kontent Smart Link SDK

    licence npm downloads jsdelivr snyk

    Kontent Smart Link SDK can be used to automatically inject smart links to Kentico Kontent according to manually specified HTML data attributes on your website. It also lets you connect your website with Web Spotlight (for faster editing and preview of your content).

    Installation

    You can install this library using npm, or you can use global CDNs such as jsdelivr directly.

    npm

    npm i @kentico/kontent-smart-link
    

    UMD Bundles

    When using the UMD bundle and including this library inside the script tag of your HTML page, you can then find an SDK instance under the KontentSmartLink global variable. JS bundle and its minified version are distributed in dist folder.

    • kontent-smart-link.umd.min.js
    • kontent-smart-link.umd.js

    CDN

    kontent-smart-link.umd.js

    Gzip browser bundle

    https://cdn.jsdelivr.net/npm/@kentico/kontent-smart-link@latest/dist/kontent-smart-link.umd.js
    
    kontent-smart-link.umd.min.js

    Gzip browser bundle

    https://cdn.jsdelivr.net/npm/@kentico/kontent-smart-link@latest/dist/kontent-smart-link.umd.min.js
    

    Usage

    Kontent Smart Link SDK parses manually specified HTML data attributes on your webpage and automatically injects smart links to Kentico Kontent. Injecting smart links to Kontent means that all elements marked with special data attributes will become interactive (handle clicks/redirect to Kontent/navigate from the preview in Web Spotlight/etc.). The type of injected smart link depends on used data attributes, their hierarchy, and context (Web Spotlight).

    Data attributes

    Kontent Smart Link SDK highly depends on a set of manually specified data attributes in your HTML markup. That is why it won't work properly without those attributes. The SDK won't add the data attributes to your HTML, you must add them yourself so that SDK will then be able to use them as a source of data (e.g. Kontent project ID, element code name, etc.) when injecting the smart links.

    Available data attributes

    Attribute Value Description
    data-kontent-project-id guid Kontent project/environment ID.
    data-kontent-language-codename string Kontent language codename.
    data-kontent-item-id guid Content item ID.
    data-kontent-component-id guid Content component ID.
    data-kontent-element-codename string Content type element codename.
    data-kontent-add-button - Specifies that node should have add-button rendered near it.
    data-kontent-add-button-insert-position start | before | after | end Specifies the insert position of an item/content component added using add button.
    data-kontent-add-button-render-position bottom-start | bottom | bottom-end | left-start | left | left-end | top-start | top | top-end | right-start | right | right-end Specifies visual location of add button.
    data-kontent-disable-features highlight Specifies that the selected node should not have highlight (which includes edit buttons). Useful when there are too many smart links on your page.

    Data attributes hierarchy

    Although it is possible to put all previously specified data attributes on the same DOM node, you don't have to do it. We recommend you set data attributes hierarchically so that you don't have to duplicate the same attributes.

    For example, your webpage probably represents one specific project in Kontent, which means that you can place data-kontent-project-id attribute on your <body> element or another wrapping DOM node so that all descendant nodes inherit this project ID. The same could be true for a language code name. If your page uses only 1 language variant at a time, you could place your data-kontent-language-codename attribute next to your data-kontent-project-id from a previous step. But remember, that since language variant is relevant to some specific project, data-kontent-language-codename attribute should always be on the same element as data-kontent-project-id attribute or on some of its descendants. After that, you can find all DOM nodes that represent Kontent items and place data-kontent-item-id attribute on them. Then inside those nodes, you can find all descendants that represent some element of the Kontent item and put data-kontent-element-codename attribute on them. In the case of Rich Text elements and Linked Items elements, there could be other content items or content components inside them, which have their own elements and so on.

    Content components

    Content component is single-use content, that is also sometimes referred to as one-off, channel-specific, or non-reusable. Content components exist only within a specific rich text element in your content items and become their integral part. This means you won't find components in your list of items in Content Inventory in Kontent.

    You should use data-kontent-component-id attribute to specify that something represents a content component in your HTML so that the SDK knows that this item has no separate page in the Kontent and must be opened in the context of its parent content item.

    Smart link types

    Currently, there are 4 types of smart links supported by Kontent Smart Link SDK. All of them require certain data attributes to be specified in HTML markup of your webpage. Please note, that most of those smart link types are only available and visible inside Web Spotlight preview iframe.

    Edit element button

    Edit element button allows you to edit a specific element of a content item by clicking on it in preview. Inside Web Spotlight, this will lead to In-Context editor being opened, and the selected element will be scrolled into view. Outside Web Spotlight, you will be redirected to Kontent item editor.

    Data attributes: data-kontent-project-iddata-kontent-language-codenamedata-kontent-item-iddata-kontent-component-id?data-kontent-element-codename.

    Environment: This feature is available both inside and outside Web Spotlight.

    Edit content component button

    Edit content component button allows you to edit a specific content component by clicking on it in preview. This will lead to In-Context editor being opened, and the selected content component scrolled into view.

    Data attributes: data-kontent-project-iddata-kontent-language-codenamedata-kontent-item-iddata-kontent-component-id.

    Environment: This feature is only available inside Web Spotlight.

    Edit content item button

    Edit content item button allows you to edit a specific content item by clicking on it in preview. This will lead to In-Context editor being opened.

    Data attributes: data-kontent-project-iddata-kontent-language-codenamedata-kontent-item-id.

    Environment: This feature is only available inside Web Spotlight.

    Add button

    Add button allows you to add content to your page right from your preview. It supports both Linked items elements and Rich Text elements.

    Environment: This feature is only available inside Web Spotlight.

    Fixed add button

    Data attributes: data-kontent-project-iddata-kontent-language-codenamedata-kontent-item-iddata-kontent-component-id?data-kontent-element-codename(RTE or LIE) → data-kontent-add-button & data-kontent-add-button-render-position? & data-kontent-add-button-insert-position=start|end .

    Relative add button

    Relative add button allows you to add content relatively to some existing content in your Rich Text element or Linked item element. For example, you can insert a new content component after or before the existing content component in RTE. To turn add button into a relative add button, you need to set insert position to before or after and provide target id on the same node using data-kontent-item-id or data-kontent-component-id attribute.

    Data attributes: data-kontent-project-iddata-kontent-language-codenamedata-kontent-item-iddata-kontent-component-id?data-kontent-element-codename(RTE or LIE) → data-kontent-item-id|data-kontent-component-id(target item) & data-kontent-add-button & data-kontent-add-button-render-position? & data-kontent-add-button-insert-position=before|after.

    SDK Initialization

    After all data attributes have been set, you can initialize Kontent Smart Link SDK on your website. You can use initialize or initializeOnLoad method in order to do it. Both of the previously mentioned methods return an instance of initialized SDK (initializeOnLoad returns a Promise resolving to an instance). The main difference between the two methods is that the initializedOnLoad method will wait for the page to load before initializing the SDK. This can be useful when you want to initialize the SDK in the head section of your webpage when the page has not been fully loaded yet.

    Kontent Smart Link SDK uses multiple event listeners, timeouts, observers to track the position of the relevant elements, so please always call .destroy() method to dispose all of those side effects before trying to initialize the SDK again (e.g. inside useEffect cleanup function) to avoid memory leaks.

    Configuration

    Both initialization methods take an optional configuration argument, that you can use to configure the SDK. You can also use instance setConfiguration method to update configuration of initialized SDK.

    Attribute Default Description
    debug false When it's set to true, enables all debug logs. Can be useful to get more information about how the SDK works inside, but can affect performance.
    defaultDataAttributes { projectId: undefined, languageCodename: undefined } Default values for data attributes, which are only used when those data attributes are not found in DOM during data attributes parsing process. For now, only projectId and languageCodename attributes are supported.
    queryParam ksl-enabled Name of the query parameter that must be present in the URL to turn the smart link injection on. It is not necessary for query parameter to have a truthy value (just the presence of this query parameter is checked). If set to falsy value ('', null), the smart link injection will always be enabled. Query parameter is only used outside Web Spotlight.

    Customization

    The following custom CSS properties can be used to customize the visuals of the SDK output.

    Custom property Default Description
    --ksl-color-background-default rgba(255, 255, 255, 1) Default background color used in toolbar and popover.
    --ksl-color-background-default-disabled rgba(223, 223, 223, 1) Disabled background color for buttons inside toolbar and popover.
    --ksl-color-background-default-hover rgba(21, 21, 21, 0.1) Hover background color for buttons inside toolbar and popover.
    --ksl-color-background-default-selected rgba(255, 240, 239, 1) Selected background color for buttons inside toolbar and popover.
    --ksl-color-background-secondary rgba(20, 22, 25, 1) Secondary background color used in tooltips.
    --ksl-color-primary rgba(219, 60, 0, 1) Primary color used as a hover border color in highlights and as a background color in add buttons.
    --ksl-color-primary-hover rgba(149, 48, 0, 1) Primary color used as a hover background color in add buttons.
    --ksl-color-primary-transparent rgba(219, 60, 0, 0.5) Primary color with transparency used as a default border color in highlights.
    --ksl-color-text-default rgba(255, 255, 255, 1) Text color used on a default background (buttons inside toolbar and popover).
    --ksl-color-text-default-disabled rgba(140, 140, 140, 1) Disabled text color used on a default background.
    --ksl-color-text-secondary rgba(21, 21, 21, 1) Text color used inside tooltips and add buttons.
    --ksl-shadow-default 0 8px 32px rgba(16, 33, 60, 0.24), 0 0 8px rgba(0, 0, 0, 0.03) Default shadow for toolbar.
    --ksl-shadow-primary 0 8px 10px rgba(219, 60, 0, 0.2), 0 6px 20px rgba(219, 60, 0, 0.12), 0 8px 14px rgba(219, 60, 0, 0.14) Shadow for add buttons.

    For example, if you want to override all SDK colors and shadows for all SDK elements on the page, you can do it by changing the values of all available custom properties of a :root element in your CSS or inside a new <style> tag on your page.

    :root {
        --ksl-color-background-default: rgba(4, 102, 200, 1);
        --ksl-color-background-default-disabled: rgba(2, 62, 125, 1);
        --ksl-color-background-default-hover: rgba(0, 40, 85, 0.1);
        --ksl-color-background-secondary: rgba(2, 62, 125, 1);
        --ksl-color-background-default-selected: rgba(3, 83, 164, .1);
        --ksl-color-primary: rgba(4, 102, 200, 1);
        --ksl-color-primary-transparent: rgba(4, 102, 200, 0.5);
        --ksl-color-primary-hover: rgba(2, 62, 125, 1);
        --ksl-color-text-default: rgba(255, 255, 255, 1);
        --ksl-color-text-default-disabled: rgba(51, 65, 92, 1);
        --ksl-color-text-secondary: rgba(255, 255, 255, 1);
        --ksl-shadow-default: 0 8px 32px rgba(0, 24, 69, 0.24), 0 0 8px rgba(0, 0, 0, 0.03);
        --ksl-shadow-primary: 0 8px 10px rgba(4, 102, 200, 0.2), 0 6px 20px rgba(4, 102, 200, 0.12), 0 8px 14px rgba(4, 102, 200, 0.14);
    }

    Using SDK inside and outside Web Spotlight

    When Kontent Smart Link SDK is used outside Web Spotlight, it listens to the query parameters in the URL to toggle smart link injection. The name of the query parameter defaults to ksl-enabled, but can be changed using the queryParam configuration argument of the initialize or initializeOnLoad methods. Only the presence of the query parameter is checked and its value is ignored, so all the following options are valid: ?ksl-enabled=true, ?ksl-enabled=false , ?ksl-enabled, etc.

    If you set the query parameter to a false value (null, ""), then the SDK will always be enabled.

    If the SDK detects it is run inside an iframe at the beginning of the initialization process, it will try to connect to the Web Spotlight by sending an iframe message to the parent window. If Web Spotlight response is received, query parameter detection will be turned off and additional features (more in the smart link types section) will be enabled. Else the SDK will continue to work as if it was outside Web Spotlight (query parameters detection, redirects to Kontent, etc.)

    IFrame Communication

    When running inside Web Spotlight preview iframe, Kontent Smart Link SDK enables several additional features and sends iframe messages instead of redirecting user to Kontent page. All message types are listed below.

    Message Data Origin Description
    kontent-smart-link:initialized { projectId: string | null, languageCodename: string | null, enabled: boolean } SDK This message is sent by the SDK when it is initialized.
    kontent-smart-link:initialized:response - Host This message is sent by the host as a response to initialized message.
    kontent-smart-link:status { enabled: boolean } Host This message is used to toggle the SDK features.
    kontent-smart-link:element:clicked { projectId: string, languageCodename: string, itemId: string, contentComponentId?: string, elementCodename: string } SDK This message is sent by the SDK when element with data-kontent-element-codename attribute is clicked.
    kontent-smart-link:content-component:clicked { projectId: string, languageCodename: string, itemId: string, contentComponentId: string } SDK This message is sent by the SDK when element with data-kontent-component-id attribute is clicked.
    kontent-smart-link:content-item:clicked { projectId: string, languageCodename: string, itemId: string } SDK This message is sent by the SDK when element with data-kontent-item-id attribute is clicked.
    kontent-smart-link:add:initial { projectId: string, languageCodename: string, itemId: string, contentComponentId?: string, elementCodename: string, insertPosition: { targetId?: string, placement: 'start' | 'end' | 'before' | 'after', } } SDK This message is sent by the SDK when add button is clicked.
    kontent-smart-link:add:initial:response { elementType: 'LinkedItems' | 'RichText' | 'Unknown', isParentPublished: boolean, permissions: Map<string,string> } Host This message is sent by the host as a response to initial add button click.
    kontent-smart-link:add:action { projectId: string, languageCodename: string, itemId: string, contentComponentId?: string, elementCodename: string, action: string, insertPosition: { targetId?: string, placement: 'start' | 'end' | 'before' | 'after', } } SDK This message is sent by the SDK when add button action is clicked.

    Nested iframes

    There may be some cases when you would want to put your page into another iframe (e.g. to simulate a mobile device resolution). But if you then load your nested iframe page inside Web Spotlight preview tab, it would act as if it wasn't inside Web Spotlight. This happens because the initialization message sent from SDK to Kontent gets lost in the parent iframe. You can use the following workaround to fix the issue: https://github.com/Kentico/kontent-smart-link/issues/16.

    Examples

    HTML & UMD & CDN

    <html>
      <head>
        <title>Kontent Smart Link - HTML example</title>
        <script type="text/javascript"
                src="https://cdn.jsdelivr.net/npm/@kentico/kontent-smart-link@2.0.0/dist/kontent-smart-link.umd.min.js"></script>
        <script type="text/javascript">
          KontentSmartLink.initializeOnLoad({ queryParam: "preview" });
        </script>
      </head>
      <body data-kontent-project-id="1d50a0f7-9033-48f3-a96e-7771c73f9683" data-kontent-language-codename="en-US">
        <nav class="navigation" data-kontent-item-id="6ea11626-336d-47e5-9f35-2d44fa1ad6d6">
          <img class="navigation__logo" data-kontent-element-codename="logo" />
          <ul
            class="navigation__list"
            data-kontent-element-codename="navigation"
            data-kontent-add-button
            data-kontent-render-position="left"
            data-kontent-insert-position="start"
          >
            <li class="navigation__list-item" data-kontent-component-id="036acd8f-5e6d-4023-b0f8-a4b8e0b573b1">
              <span data-kontent-element-codename="title">Home</span>
            </li>
            <li class="navigation__list-item" data-kontent-component-id="f539f1bc-9dc4-4df5-8876-dbb1de5ae6eb">
              <span data-kontent-element-codename="title">About us</span>
            </li>
          </ul>
        </nav>
        <div
          class="page"
          data-kontent-item-id="af858748-f48a-4169-9b35-b10c9d3984ef"
          data-kontent-element-codename="page_content"
        >
          <div
            class="section"
            data-kontent-component-id="51a90561-9084-4d32-9e34-80da7c88c202"
            data-kontent-add-button
            data-kontent-add-button-render-position="bottom"
            data-kontent-add-button-insert-position="after"
          >
            <img class="home__banner" data-kontent-element-codename="image" />
            <h1 data-kontent-element-codename="title">Home page</h1>
          </div>
          <div
            class="section"
            data-kontent-component-id="23e657d2-e4ce-4878-a77d-365db46c956d"
            data-kontent-add-button
            data-kontent-add-button-render-position="bottom"
            data-kontent-add-button-insert-position="after"
          >
            <p data-kontent-element-codename="text">...</p>
          </div>
        </div>
      </body>
    </html>

    ES6

    import KontentSmartLink from "@kentico/kontent-smart-link";
    
    // This is just an example of SDK initialization inside ES6 module.
    // HTML markup should still contain all necessary data-attributes.
    const kontentSmartLink = KontentSmartLink.initializeOnLoad({
      debug: true,
      defaultDataAttributes: {
        projectId: "1d50a0f7-9033-48f3-a96e-7771c73f9683",
        languageCodename: "default",
      },
      queryParam: "ksl-preview"
    });

    Next.js

    In order to use the SDK with the Next.js framework you can either initialize it separately on each page or initialize it once for the whole application using the _app.jsx file. Do not forget to destroy() SDK for it to work properly.

    // _app.jsx
    import KontentSmartLink from "@kentico/kontent-smart-link";
    
    const MyApp = ({
      Component,
      pageProps
    }) => {
      useEffect(() => {
        // This is just an example of SDK initialization inside ES6 module.
        // HTML markup should still contain all necessary data-attributes (e.g. PageSection component).
        const kontentSmartLink = KontentSmartLink.initialize({
          defaultDataAttributes: {
            projectId: "1d50a0f7-9033-48f3-a96e-7771c73f9683",
            languageCodename: "default",
          },
          queryParam: "preview-mode"
        });
    
        return () => {
          kontentSmartLink.destroy();
        };
      });
    
      return (
        <PageSection>
          <Component {...pageProps} />
        </PageSection>
      );
    };
    
    const PageSection = (props) => {
      return (
        <div data-kontent-item-id="3fdbc5a0-13e6-4516-82c3-50bf4db43644">
          <div data-kontent-element-codename="page_section__content">
            {props.children}
          </div>
        </div>
      );
    };

    Gatsby

    You can either initialize the SDK on every page or use a layout to initialize the SDK while using Gatsby. Do not forget to destroy() SDK for it to work properly.

    // src/components/layout.jsx
    import KontentSmartLink from "@kentico/kontent-smart-link";
    
    export default function Layout({ children }) {
      useEffect(() => {
        // This is just an example of SDK initialization inside ES6 module.
        // HTML markup should still contain all necessary data-attributes (e.g. .layout element).
        const kontentSmartLink = KontentSmartLink.initialize({
          queryParam: "enable-ksl-sdk"
        });
        return () => {
          kontentSmartLink.destroy();
        };
      });
    
      return (
        <div
          class="layout"
          data-kontent-project-id="1d50a0f7-9033-48f3-a96e-7771c73f9683"
          data-kontent-language-codename="en-US"
        >
          {children}
        </div>
      );
    }

    Tests

    Unit tests

    Since this SDK highly depends on browser APIs, the unit tests are run by Karma test runner (+ Jasmine) inside Chrome browser. To run all tests in a watch mode you can use the npm run test:unit command. To run all tests only once you can use the npm run test:unit:ci command. All unit tests are located in the test-browser folder.

    Visual regression tests

    Visual regression testing is implemented using Storybook and Loki. Each story in Storybook represents a test case, which is then used by Loki to generate screenshots. In order to run visual regression tests you need to start Storybook using the npm run storybook command and then start loki testing using the npm run test:visual command. Or you can use the npm run test:visual:ci command to automatically start the Storybook server in a CI mode and run visual tests.

    Visual regression tests use the built version of SDK, so before running them make sure you rebuild the SDK after the last change you made. You can this using the npm run build command or using the npm run dev command to start build in a watch mode.

    Breaking changes

    All breaking changes can be found in a separate markdown file.

    Feedback & Contribution

    Feedback & Contributions are welcomed. Feel free to take/start an issue & submit PR.

    Install

    npm i @kentico/kontent-smart-link

    DownloadsWeekly Downloads

    1,290

    Version

    2.1.0

    License

    MIT

    Unpacked Size

    1.68 MB

    Total Files

    149

    Last publish

    Collaborators

    • simply007
    • enngage
    • janck
    • kentico_tomasw
    • jirik
    • vladislavb-kentico
    • xp-peterp
    • honzabarton
    • hom3r
    • martins1
    • xperience-npmjs-publisher