zoid

repository·main·Indexed 24 days ago

https://github.com/krakenjs/zoid

A cross-domain component toolkit that allows developers to render components in iframes or popups while passing props and callbacks seamlessly. It enables sharing secure, framework-agnostic functionality across different domains using a 'data-down, actions up' pattern, abstracting away the complexity of postMessage. zoid provides drivers for integration with React, Vue 2/3, Angular 1/2+, and Glimmer.

Tokens
19.7K
Snippets
62
Records
103
Agent score
79%

What's inside @krakenjs/zoid

  1. Access component props inside the iframe using window.xprops

    main

    When implementing the logic inside the component (the code running within the iframe), you can access the properties passed down from the parent window via the window.xprops object.

    Additionally, you can trigger callbacks defined in the props by calling them directly on window.xprops. Zoid transparently converts these function calls into post-messages that are relayed back to the parent window.

    // Accessing a prop
    if (window.xprops.prefilledEmail) {
      document.querySelector("#email").value = window.xprops.prefilledEmail;
    }
    
    // Calling a callback prop to notify the parent
    window.xprops.onLogin(email);
  2. How zoid works: Cross-domain components and the mental model

    main

    zoid is a toolkit for building cross-domain components using iframes or popups. It follows a 'data-down, actions up' pattern, similar to modern UI frameworks, but adapted for cross-domain security and communication.

    Core Concepts

    • Cross-Domain Isolation: Instead of loading a script directly into a host page (which poses security risks and framework compatibility issues), zoid renders your component in an iframe or popup. This protects your secure data and logic from the host site.
    • Seamless Communication: zoid abstracts away the complexity of postMessage. You pass data and callbacks as a standard JavaScript object. The child accesses these via window.xprops.
    • Framework Agnostic: You can build your component using any framework (React, Vue, Angular, etc.) or vanilla JavaScript. Zoid handles the bridge between the host and the iframe. On the parent side, zoid can automatically generate bindings for React or Angular to make the cross-domain component feel like a native component.
    • When to use zoid: Use zoid when you need to share functionality (like a login widget, a payment button, or a secure form) with third-party websites where you cannot guarantee the host's framework or security environment.
  3. Understand the `window.xprops` object

    main
    In a Zoid child window or iframe, window.xprops is automatically populated with props from the parent. It serves as the primary interface for the child component to interact with its parent, manage its own lifecycle, and access component metadata like its unique ID (uid) and tag.
  4. Use zoid components in React / JSX

    main

    To use a zoid component in a React application, use the .driver("react", options) method on your component spec. This creates a React-compatible component. You must provide the React and ReactDOM instances in the options object.

    Once created, you can use the component as a standard JSX element, passing props just like any other React component.

    let MyReactLoginComponent = MyLoginComponent.driver("react", {
      React: React,
      ReactDOM: ReactDOM,
    });
    
    // Inside a render method:
    <MyReactLoginComponent prefilledEmail='foo@bar.com' onLogin={onLogin} />
  5. Use zoid components in Angular

    main

    To use a zoid component in Angular, follow these two steps:

    1. Register the component: Add the component's tag name as a dependency to your Angular module.
    2. Use in templates: Include the custom HTML tag in your templates. Note that you must use dasherized versions of your prop names (e.g., prefilledEmail becomes prefilled-email).
  6. Quick start with zoid: Create and use a cross-domain component

    main

    To use zoid, you define a component using zoid.create(), which specifies a custom HTML tag and the URL where the component's implementation lives. This definition must be shared by both the parent page and the child page (the iframe content).

    1. Define the component

    Both the parent and the child must run this code:

    var MyLoginComponent = zoid.create({
      tag: "my-login-component",
      url: "http://www.my-site.com/my-login-component",
    });

    2. Render on the parent page

    On the parent page, you call the component function with the desired props (including callbacks) and then call .render(selector) to mount it into a DOM element.

    3. Implement in the child (iframe)

    Inside the iframe, you access the passed props via window.xprops. You can read data down from the parent and call functions back up to the parent by invoking these xprops methods.

    Note: The component implementation is 'data-down, actions up' style, where the parent passes state and the child triggers callbacks.

    // 1. Define the component (shared by parent and child)
    var MyLoginComponent = zoid.create({
      tag: "my-login-component",
      url: "http://www.my-site.com/my-login-component",
    });
    
    // 2. Render on the parent page
    <div id="container"></div>
    <script src="script-where-my-login-component-is-defined.js"></script>
    <script>
        MyLoginComponent({
            prefilledEmail: 'foo@bar.com',
            onLogin: function(email) {
                console.log('User logged in with email:', email);
            }
        }).render('#container');
    </script>
    
    // 3. Implement in the iframe
    <input type="text" id="email" />
    <input type="password" id="password" />
    <button id="login">Log In</button>
    
    <script src="script-where-my-login-component-is-defined.js"></script>
    <script>
        var email = document.querySelector('#email');
        var password = document.querySelector('#password');
        var button = document.querySelector('#login');
    
        email.value = window.xprops.prefilledEmail;
    
        function validUser (email, password) {
          return email && password;
        }
    
        button.addEventListener('click', function() {
            if (validUser(email.value, password.value)) {
                window.xprops.onLogin(email.value);
            }
        });
    </script>
  7. Use only iframe support (without popups)

    main

    If you do not require popup support (which includes extra logic for legacy browser compatibility like IE), you can use a lighter version of zoid that only provides iframe support.

    Look for zoid.frame.js or zoid.frame.min.js in the dist/ folder of the package.

  8. Configure prop behavior in Zoid components

    main

    When defining props for a Zoid component, you can use several properties within the PropsDefinitionType to control how values are derived, validated, and transformed.

    Key properties available in a prop definition include:

    • alias: Allows a prop to take its value from a different key in the inputProps if the primary key is undefined.
    • value: A function that returns a derived value. It receives an object containing props, state, close, focus, event, onError, and container.
    • default: A function used to provide a default value if the prop is undefined. It receives the same context object as value.
    • type: Specifies the expected type (e.g., PROP_TYPE.ARRAY or a string like 'string'). Zoid will throw a TypeError if the value does not match.
    • required: A boolean. If not explicitly set to false, Zoid will throw an error if the prop is missing from inputProps.
    • validate: A function used for custom validation logic (only executed in __DEBUG__ mode).
    • decorate: A function used to transform the value before it is exposed. It receives the current value and the same context object as value and default.

    Note: value and default functions have access to the component's helpers (like close and focus) to allow props to react to the component's lifecycle.

  9. Define component props and domain security

    main

    In the options object passed to parentComponent, the propsDef (within options) defines how props are handled. You can control prop propagation using:

    • sendToChild: If false, this prop is kept by the parent and not sent to the child component.
    • sameDomain: If true, the prop is only sent to the child if it resides on the same domain as the parent.
    • trustedDomains: An array of domains. The prop is only sent to the child if the child's domain matches one of these entries.
  10. Understand the constraints of renderTo

    main

    When attempting to render a component to a target, Zoid enforces several security and structural rules via checkAllowRender:

    1. Adjacent Frames: If the target is not the current window, it must be an adjacent frame (it cannot be a top-level window different from the current one).
    2. Domain Matching: If the target is a different domain, it must match the component's childDomainMatch configuration. If it is the same domain, the check passes.
    3. Container Type: If a container is provided, it must be a string selector. Passing a DOM element directly will result in an error.
  11. Understand Zoid component props and lifecycle events

    main

    Zoid components use a specific set of props for configuration and lifecycle management. These are divided into input props (passed to the component) and child props (available to the component's children).

    Lifecycle Event Props

    These event handlers allow you to react to the component's lifecycle. Most are decorated to ensure they only fire once.

    • onDisplay: Fired when the component is displayed.
    • onRendered: Fired when the component has been rendered.
    • onRender: Fired during the render process.
    • onPrerendered: Fired when the component is prerendered.
    • onPrerender: Fired during the prerender process.
    • onClose: Fired when the component is closed.
    • onDestroy: Fired when the component is destroyed.
    • onResize: Fired when the component is resized.
    • onFocus: Fired when the component gains focus.
    • onError: Fired when an error occurs (receives the error object).
    • onBfcacheCache: Fired when the page is being cached in the browser's Back/Forward Cache.
    • onBfcacheRestore: Fired when the page is restored from the Back/Forward Cache (receives cachedDurationMs).
    • onProps: A specialized prop for handling property updates. It provides a way to cancel updates.

    Component Control Props (Child Props)

    Children of a Zoid component can access these methods to interact with the parent or the component instance:

    • close(): Closes the component.
    • focus(): Focuses the component.
    • show(): Shows the component.
    • hide(): Hides the component.
    • resize({ width, height }): Resizes the component.
    • export(data): Exports data from the child to the parent.
    • getParent(): Returns the parent's CrossDomainWindowType.
    • getParentDomain(): Returns the parent's domain string.
    • getSiblings(): Returns an array of sibling components.
  12. Manage data references with getUIDRef and getRawRef

    main

    Zoid provides mechanisms to handle data via references, which is essential when using passByReference in cross-domain scenarios.

    Reference Types

    • UID Reference (REFERENCE_TYPE.UID): The actual data is stored in a global reference store (window.references) on the local window. The reference object only contains a unique ID (uid). This is used to avoid sending large payloads over the wire.
    • Raw Reference (REFERENCE_TYPE.RAW): The data is embedded directly within the reference object (val).

    Key Functions

    • getUIDRef(val): Creates a UID reference by storing the value in the local window's reference store and returning a { type: 'uid', uid: '...' } object.
    • getRawRef(val): Creates a raw reference by returning { type: 'raw', val }.
    • getRefValue(win, ref): Retrieves the actual value from either the raw object or the provided window's reference store using the UID.
    • cleanupRef(win, ref): Removes a UID reference from the window's reference store to prevent memory leaks.