# Quickstart

Struct PIM allows you to extend your PIM environment with custom apps that can create a more interactive user experience. These custom apps can run as iframe-based widgets inside the PIM UI, enabling you to create custom widgets to enhance your workflow and experience.

In this quickstart guide, we will show how to set up a minimal custom widget app using TypeScript, Struct UI for styling, and the Struct Extension SDK to communicate with the PIM.

### 1. Initialize a TypeScript project with Vite

```bash
mkdir my-pim-integration
cd my-pim-integration
npm create vite@latest .
```

* When prompted, choose:
  * **Framework:** `vanilla`
  * **Variant:** `TypeScript`

This sets up a clean TypeScript project with Vite, ready for framework-agnostic development.

### 2. Install PIM SDK and UI Packages

Install the required packages:

```bash
npm install @structdk/extension-sdk @structdk/ui @structdk/struct-icon
```

You can now import these packages in your `src/main.ts`.

### 3. Setting up a minimal extension

In `src/main.ts`, set up the SDK and import the `@structdk/ui` and `@structdk/struct-icon` packages:

```typescript
import '@structdk/ui/dist/struct-ui.css';
import '@structdk/struct-icon/font/struct-icon-24.css'
import { createStructSDK } from '@structdk/extension-sdk';
import type { TabContextPayload } from '@structdk/extension-sdk';

async function init() {
  // 1. SDK instance
  const struct = createStructSDK({ hostOrigin: 'https://your-struct-instance.struct.com' });

  // 2. Get context
  const ctx = await struct.actions.getContext<TabContextPayload>();
  console.log('Entity:', ctx.entityType, ctx.entityId);
  console.log('Slug:', ctx.slug);

  // 3. Auto-resize
  struct.actions.enableAutoResize({ maxHeight: 800 });

  // 4. Event listeners
  struct.events.onEntityChangedEvent(payload => console.log('Entity updated:', payload.entityId));
  struct.events.onLanguageChangedEvent(payload => console.log('Language:', payload.currentLanguage));

  // 6. Cleanup
  struct.destroy();
}

// 7. Initialize app on window load
window.addEventListener('load', () => {
  init();
});
```

{% hint style="info" %}
For more details refer to the documentation for the following packages: <https://www.npmjs.com/package/@structdk/extension-sdk>

<https://www.npmjs.com/package/@structdk/struct-icon>

<https://www.npmjs.com/package/@structdk/ui>
{% endhint %}

### 4. Create UI component

Create reusable UI component using Struct UI and Struct Icon. For example, `src/components/hello.ts`:

```typescript
export function HelloWorld(container: HTMLElement, onClick: () => void) {
  container.innerHTML = `
    <div class="card p-4 space-y-4">
      <h1 class="text-xl font-semibold">Hello World</h1>
      <button class="btn btn-primary">
        <span class="si-24 si-button-play" aria-hidden="true"></span>
        Click me
      </button>
    </div>`;

  const button = container.querySelector<HTMLButtonElement>('.btn');
  button?.addEventListener('click', onClick);
}
```

### 5. Render the component in your app

Import the component and render it in `src/main.ts`:

```typescript
import '@structdk/ui/dist/struct-ui.css';
import '@structdk/struct-icon/font/struct-icon-24.css'
import { createStructSDK } from '@structdk/extension-sdk';
import type { TabContextPayload } from '@structdk/extension-sdk';
import { HelloWorld } from './components/hello';

async function init() {
  // 1. SDK instance
  const struct = createStructSDK({ hostOrigin: 'https://your-struct-instance.struct.com' });

  // 2. Get context
  const ctx = await struct.actions.getContext<TabContextPayload>();
  console.log('Entity:', ctx.entityType, ctx.entityId);
  console.log('Slug:', ctx.slug);

  // 3. Auto-resize
  struct.actions.enableAutoResize({ maxHeight: 800 });

  // 4. Event listeners
  struct.events.onEntityChangedEvent(payload => console.log('Entity updated:', payload.entityId));
  struct.events.onLanguageChangedEvent(payload => console.log('Language:', payload.currentLanguage));

  // 5. Render Hello World
  const app = document.getElementById('app');
  if (app) {
    
      const helloContainer = document.createElement('div');
      app.appendChild(helloContainer);

    HelloWorld(helloContainer, () => {
      struct.actions.showSnackbarMessage({
        message: 'Hello World clicked!',
        placement: 'top',
        isError: false
      });
    });
  }

  // 6. Cleanup
  struct.destroy();
}

// 7. Initialize app on window load
window.addEventListener('load', () => {
  init();
});
```

### 6. Integrate app

1. Click "Create App"-button to begin setting up the custom app.

<figure><img src="https://2141378775-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuUonpFWM7AJ0xVVXV1tr%2Fuploads%2Fqwcd8Ox70nImsgOWeoLF%2Fimage.png?alt=media&#x26;token=05cb1ffb-7d19-4f9a-bc4f-a9be3b61fd47" alt=""><figcaption></figcaption></figure>

2. Configure the General settings for the app.

<figure><img src="https://2141378775-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuUonpFWM7AJ0xVVXV1tr%2Fuploads%2FXDNc5oGe4HCQVFUYOyzf%2Fimage.png?alt=media&#x26;token=5de822e1-021c-47b2-8894-53e991a10eb7" alt=""><figcaption></figcaption></figure>

3. Setup extension points.

<figure><img src="https://2141378775-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuUonpFWM7AJ0xVVXV1tr%2Fuploads%2FJPC9PjfCwjjIlHTno7xL%2Fimage.png?alt=media&#x26;token=f4726d29-ba1b-4415-8f45-46248acc44fb" alt=""><figcaption></figcaption></figure>

4. Embed the new external widget in the dashboard.

<figure><img src="https://2141378775-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuUonpFWM7AJ0xVVXV1tr%2Fuploads%2FAAbugfNloCbUbWAFPCp8%2Fimage.png?alt=media&#x26;token=5532105b-e93c-4caf-a41a-9f4723b19ae5" alt=""><figcaption></figcaption></figure>

This wraps up the flow for setting up and integrating an app to the PIM.
