Building custom components

This guide walks you through creating a custom component in the SuperAnnotate Multimodal Editor. In this example, you will build a component that:

  • Accepts a text URL input.
  • Transforms the input into a clickable hyperlink.
  • Optionally displays the corresponding webpage in an integrated preview.

This approach is useful when your annotation workflow requires linking to external resources or private data. By creating a clickable hyperlink, annotators can easily access external content with minimal interruption to their annotation tasks.


Prerequisites

  • A SuperAnnotate account with Multimodal project support.
  • Basic understanding of HTML, JavaScript, and Python.
  • Familiarity with the UI Builder and Code Editor in SuperAnnotate.

Overview

You will create three main components:

  1. Text Input Component: For entering a URL.
  2. Web Component: Contains the custom HTML and JavaScript to transform the URL into a clickable hyperlink.
  3. (Optional) URL Component: Displays the webpage directly within SuperAnnotate, allowing you to confirm correct behavior and preview the external site.

After setting up these components in the UI Builder, you will add custom logic in the Code Editor to handle dynamic input changes and communication with the Web Component.


Step 1: Set Up Your UI in the Builder

  1. In your Multimodal Editor, open the UI Builder.
  2. Add a Grid from the left panel to structure your custom UI elements:
    • Drag a Grid component onto the canvas.
    • Select the Grid and, in the Component Properties panel on the right, change its component_id to something intuitive, such as url_grid.

Why use a Grid?

A Grid helps logically group your inputs (Text Input, URL preview, Web Component) in one place, making it easier to manage and scale.

Step 2: Add and Configure Components

2.1 Text Input Component

  1. Drag a Text Input component into the first column of your Grid.
  2. In the component Properties panel, rename its component ID to url_path.
  3. Under Label, replace the default text with URL.
  4. (Optional) Remove or customize the Placeholder if you do not need placeholder text.
  5. Adjust Max. length if you expect very long URLs.

Tip: Use meaningful component_ids to align with your dataset variable names (e.g., url_path if your CSV/JSON key is url_path).

2.2 Web Component (Clickable Hyperlink)

  1. Drag a Web Component into the second column of your Grid.
  2. Rename its component_id to hyperlink.
  3. Click the Edit button on the top-right of the Web Component to open the code editor for this component (HTML/JS).

You will add HTML and JavaScript here in Step 3.

2.3 (Optional) URL Component

  1. (Optional) Add another column to the Grid by selecting Add Column in the Component Properties of the Grid.
  2. Drag a URL Component into this new column.
  3. Rename its component ID to url.
  4. The Source URL field can be left blank to be updated dynamically later.

Note: Resizing the URL Component in a production environment provides a better viewing experience for annotators.

Step 3: Add HTML/JS Code in the Web Component

Inside the Web Component’s editor, you will define the structure and behavior of your hyperlink. Below is a sample code snippet to paste into the Web Component:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Clickable Link Component</title>
    <style>
        /* Optional: Add some basic styling */
        body {
            font-family: Arial, sans-serif;
            padding: 10px;
        }
        #dynamicLink {
            font-size: 16px;
            color: #007BFF;
            text-decoration: none;
        }
        #dynamicLink:hover {
            text-decoration: underline;
        }
    </style>
</head>
<body>
    <a id="dynamicLink" href="#" target="_blank">Loading...</a>

    <script type="text/javascript">
        let SA;
        if ("SA" in window) {
            console.log('SA object found in window:', SA);
            SA = window.SA;
            SA.onMessage(async (message) => {
                console.log('Received message via SA.onMessage:', message);
                let data;
                try {
                    // Assume the data is a JSON string
                    data = typeof message === 'string' ? JSON.parse(message) : message;
                } catch (error) {
                    console.error('Failed to parse message data:', error);
                    return;
                }
                
                if (data && data.url) {
                    const linkElement = document.getElementById('dynamicLink');
                    linkElement.href = data.url;
                    linkElement.textContent = data.text || data.url; 
                }
            });
        }
    </script>
</body>
</html>

Key Points

  • SA.onMessage listens for messages from SuperAnnotate.
  • If a valid URL is sent, the script updates the hyperlink’s href and displays it as clickable text.

Click Save to store your changes.

Step 4: Define Messaging Logic in the Code Editor

After finalizing your UI, click Next in the top-right corner of the screen to open the Code Editor. In the Code Editor:

  1. You will see a Python script pre-populated with base functions for each component.
  2. Each component has automatically generated event handlers (e.g., on_<component-id>_change()) where you can define logic for component updates.

Below is an example of how you might structure your code. You can paste or adapt the relevant sections into the Code Editor:

from typing import List, Union
import requests
import json
import sa

# Define component references by their component_ids
input_url_path = ['url_path']        # Text Input for URL
url_url = ['url']                    # URL Component for website display
webComponent_hyperlink = ['hyperlink']  # Web Component for clickable link

# Function to send a message to the web component
def post_message_to_web_component(message):
    try:
        sa.postMessageToWebComponent(webComponent_hyperlink, message)
        print("Message sent to web component:", message)
    except Exception as e:
        print("Error sending message to web component:", e)

# Function to format and send URL data
def send_url_to_component(url, text=None):
    message = {'url': url}
    if text:
        message['text'] = text
    message_json = json.dumps(message)
    post_message_to_web_component(message_json)

def init():
    """Initialization logic for hyperlink based on the current Text Input."""
    try:
        url = str(sa.getValue(input_url_path))
        print(f"Initializing with URL: {url}")
        
        if url:
            sa.setValue(url_url, url)  # Update URL Component
            send_url_to_component(url, url)  # Send to the Web Component
        else:
            print("No URL found in 'url_path'.")
    except Exception as e:
        print(f"Error during initialization: {e}")

def on_url_path_change(path: List[Union[str, int]], value):
    """Triggered when the Text Input value changes."""
    try:
        if value:
            print(f"'url_path' changed to: {value}")
            sa.setValue(url_url, value)  # Update URL Component
            send_url_to_component(value, value)  # Send to the Web Component
    except Exception as e:
        print(f"Error handling 'url_path' change: {e}")

# Web Component event handlers
def on_hyperlink_message(path: List[Union[str, int]], value):
    print(f"Received message from hyperlink: {value}")

def on_hyperlink_wcevent(path: List[Union[str, int]], value):
    print(f"Web component event: {value}")

# Main execution
init()

Important Details

  • init() is called immediately to initialize the component if a URL is already present.
  • on_url_path_change() automatically updates the URL component and sends the new URL to the Web Component whenever the user changes the text input.

Click the Run button to execute and preview changes.

Step 5: Test and Validate

  1. Check Initialization: After running the script, verify that any existing URL is displayed or that an appropriate “No URL found” message is shown.
  2. Enter a URL: In the Preview panel, enter a URL (e.g., https://www.greenpeace.org/global/) in the Text Input field.
  3. Verify Display:
    • The URL Component should display the site if external access is allowed.
    • The Web Component should show a clickable link (usually in blue).
  4. Change the URL: Modify the URL in the Text Input field to confirm that the link and preview update dynamically.

Tip: Some sites may refuse to be displayed within the platform for security reasons (X-Frame-Options, etc.). The hyperlink will still function correctly.

Next Steps & Best Practices

  • Publish or Update: After confirming the custom component works, click the Publish (or Update) button.
  • Add Data: You can add data to the project via CSV, JSON, or JSONL. Ensure your data fields match the component_id of the Text Input component (e.g., url_path).
  • Generate Empty Items: For quick tests, generate empty items and manually enter URLs.
  • Reuse and Extend: Export the annotation UI as a JSON template to reuse in other projects.
  • View Annotation JSON: Download completed annotations to see how data is stored in JSON format, especially if you plan to integrate with downstream applications.
  • Exclude Irrelevant Components: In the UI Builder, toggle Exclude from Export for components that you do not want to appear in exported CSV/JSON files.

That’s it! You now have a fully functional custom component that transforms a user-entered URL into a clickable hyperlink, with the option to preview the webpage in real-time.