> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-rn-guide-message-privately.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Collaborative Document Bubble

> An Angular component for rendering collaborative document messages with banner images, localized text, and action buttons

The `CometChatCollaborativeDocumentBubble` component renders collaborative document messages within chat. It displays a banner image, title, subtitle, and an action button that opens the document in a new fullscreen window.

## Overview

The Collaborative Document Bubble component processes `CometChat.CustomMessage` objects of type `extension_document` to display collaborative document content:

* **Message Object Processing**: Extracts document URL from message metadata
* **Theme-aware Banner Images**: Automatically selects light/dark banner images based on current theme
* **Localized Text**: Displays title, subtitle, and button text using localization keys
* **Sender/Receiver Styling**: Supports outgoing (right-aligned) and incoming (left-aligned) visual variants
* **Action Button**: Opens the document URL in a new fullscreen window
* **Accessibility**: Full keyboard navigation and screen reader support

<Info>
  **Live Preview** — Default collaborative document bubble preview.
  [Open in Storybook ↗](https://storybook.cometchat.io/angular/?path=/story/components-bubbles-message-bubble--collaborative-document)
</Info>

<iframe src="https://storybook.cometchat.io/angular/iframe.html?id=components-bubbles-message-bubble--collaborative-document&viewMode=story&shortcuts=false&singleStory=true" className="w-full rounded-xl" loading="lazy" style={{height: "600px", border: "1px solid #e0e0e0"}} title="CometChat Collaborative Document Bubble — Default" allow="clipboard-write" />

## Basic Usage

### Simple Document Message

```typescript expandable theme={null}
import { Component } from '@angular/core';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import { 
  CometChatCollaborativeDocumentBubbleComponent, 
  MessageBubbleAlignment 
} from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-document-message',
  standalone: true,
  imports: [CometChatCollaborativeDocumentBubbleComponent],
  template: `
    <cometchat-collaborative-document-bubble
      [message]="documentMessage"
      [alignment]="MessageBubbleAlignment.LEFT"
    ></cometchat-collaborative-document-bubble>
  `
})
export class DocumentMessageComponent {
  documentMessage!: CometChat.CustomMessage;
  MessageBubbleAlignment = MessageBubbleAlignment;
}
```

### Incoming vs Outgoing Messages

```typescript expandable theme={null}
import { Component } from '@angular/core';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import { 
  CometChatCollaborativeDocumentBubbleComponent, 
  MessageBubbleAlignment 
} from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-message-list',
  standalone: true,
  imports: [CometChatCollaborativeDocumentBubbleComponent],
  template: `
    <!-- Incoming message (left-aligned) -->
    <cometchat-collaborative-document-bubble
      [message]="incomingMessage"
      [alignment]="MessageBubbleAlignment.LEFT"
    ></cometchat-collaborative-document-bubble>

    <!-- Outgoing message (right-aligned) -->
    <cometchat-collaborative-document-bubble
      [message]="outgoingMessage"
      [alignment]="MessageBubbleAlignment.RIGHT"
    ></cometchat-collaborative-document-bubble>
  `
})
export class MessageListComponent {
  incomingMessage!: CometChat.CustomMessage;
  outgoingMessage!: CometChat.CustomMessage;
  MessageBubbleAlignment = MessageBubbleAlignment;
}
```

### With Event Handler

```typescript expandable theme={null}
import { Component } from '@angular/core';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import { CometChatCollaborativeDocumentBubbleComponent } from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-interactive-document',
  standalone: true,
  imports: [CometChatCollaborativeDocumentBubbleComponent],
  template: `
    <cometchat-collaborative-document-bubble
      [message]="documentMessage"
      (buttonClick)="onDocumentOpen($event)"
    ></cometchat-collaborative-document-bubble>
  `
})
export class InteractiveDocumentComponent {
  documentMessage!: CometChat.CustomMessage;

  onDocumentOpen(url: string): void {
    console.log('Document opened:', url);
    // Custom handling - the component already opens the URL in a new window
  }
}
```

## Properties

| Property             | Type                      | Default                       | Description                                                                                                      |
| -------------------- | ------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `message`            | `CometChat.CustomMessage` | **required**                  | The CometChat.CustomMessage object containing collaborative document metadata                                    |
| `alignment`          | `MessageBubbleAlignment`  | `MessageBubbleAlignment.LEFT` | The alignment of the message bubble. `LEFT` for incoming/receiver messages, `RIGHT` for outgoing/sender messages |
| `disableInteraction` | `boolean`                 | `false`                       | When true, disables the action button and other interactive elements within the bubble                           |

## Events

| Event         | Payload Type | Description                                                                 |
| ------------- | ------------ | --------------------------------------------------------------------------- |
| `buttonClick` | `string`     | Emitted when the action button is clicked. Contains the document URL string |

## Message Metadata Structure

The component extracts the document URL from the following metadata path:

```json theme={null}
{
  "@injected": {
    "extensions": {
      "document": {
        "document_url": "https://example.com/document/123"
      }
    }
  }
}
```

## Advanced Usage

### Complete Chat Message Component

```typescript expandable theme={null}
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import { 
  CometChatCollaborativeDocumentBubbleComponent, 
  MessageBubbleAlignment 
} from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-document-chat-message',
  standalone: true,
  imports: [CommonModule, CometChatCollaborativeDocumentBubbleComponent],
  template: `
    <div class="message-container" [class.outgoing]="isOutgoing">
      <div class="message-bubble">
        <cometchat-collaborative-document-bubble
          [message]="message"
          [alignment]="alignment"
          (buttonClick)="handleDocumentOpen($event)"
        ></cometchat-collaborative-document-bubble>
      </div>
      <div class="message-metadata">
        <span class="timestamp">{{ message.getSentAt() * 1000 | date:'short' }}</span>
      </div>
    </div>
  `,
  styles: [`
    .message-container {
      display: flex;
      flex-direction: column;
      margin-bottom: 12px;
      max-width: 70%;
    }

    .message-container.outgoing {
      align-self: flex-end;
      align-items: flex-end;
    }

    .message-bubble {
      display: inline-block;
    }

    .message-metadata {
      display: flex;
      align-items: center;
      gap: 6px;
      margin-top: 4px;
      font-size: 11px;
      color: #999;
    }
  `]
})
export class DocumentChatMessageComponent {
  @Input() message!: CometChat.CustomMessage;
  @Input() loggedInUserId!: string;

  get isOutgoing(): boolean {
    return this.message.getSender().getUid() === this.loggedInUserId;
  }

  get alignment(): MessageBubbleAlignment {
    return this.isOutgoing ? MessageBubbleAlignment.RIGHT : MessageBubbleAlignment.LEFT;
  }

  handleDocumentOpen(url: string): void {
    console.log('Document URL:', url);
    // Additional tracking or custom handling
  }
}
```

### Message List with Document Bubbles

```typescript expandable theme={null}
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import { 
  CometChatCollaborativeDocumentBubbleComponent, 
  MessageBubbleAlignment 
} from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-document-message-list',
  standalone: true,
  imports: [CommonModule, CometChatCollaborativeDocumentBubbleComponent],
  template: `
    <div class="message-list">
      @for (message of messages; track message.getId()) {
        <div class="message-wrapper" [class.outgoing]="isOutgoing(message)">
          <cometchat-collaborative-document-bubble
            [message]="message"
            [alignment]="getAlignment(message)"
            (buttonClick)="onDocumentOpen($event)"
          ></cometchat-collaborative-document-bubble>
        </div>
      }
    </div>
  `,
  styles: [`
    .message-list {
      display: flex;
      flex-direction: column;
      gap: 8px;
      padding: 16px;
    }

    .message-wrapper {
      display: flex;
      max-width: 70%;
    }

    .message-wrapper.outgoing {
      align-self: flex-end;
    }
  `]
})
export class DocumentMessageListComponent implements OnInit {
  messages: CometChat.CustomMessage[] = [];
  loggedInUser!: CometChat.User;

  async ngOnInit(): Promise<void> {
    this.loggedInUser = await CometChat.getLoggedinUser();
  }

  isOutgoing(message: CometChat.CustomMessage): boolean {
    return message.getSender().getUid() === this.loggedInUser?.getUid();
  }

  getAlignment(message: CometChat.CustomMessage): MessageBubbleAlignment {
    return this.isOutgoing(message) 
      ? MessageBubbleAlignment.RIGHT 
      : MessageBubbleAlignment.LEFT;
  }

  onDocumentOpen(url: string): void {
    console.log('Opening document:', url);
  }
}
```

## Customization

### Styling with CSS Variables

The Collaborative Document Bubble component uses CSS variables exclusively for easy customization:

```css expandable theme={null}
/* Custom document bubble styling */
cometchat-collaborative-document-bubble {
  /* Spacing */
  --cometchat-spacing-1: 4px;
  --cometchat-spacing-2: 8px;
  --cometchat-spacing-3: 12px;
  --cometchat-spacing-4: 16px;

  /* Typography */
  --cometchat-font-heading4-medium: 500 16px 'Inter';
  --cometchat-font-body-regular: 400 14px 'Inter';
  --cometchat-font-button-medium: 500 14px 'Inter';

  /* Colors - Incoming messages */
  --cometchat-background-color-01: #FFFFFF;
  --cometchat-background-color-02: #F5F5F5;
  --cometchat-text-color-primary: #141414;
  --cometchat-text-color-secondary: #666666;

  /* Colors - Outgoing messages */
  --cometchat-primary-button-background: #6852D6;
  --cometchat-primary-button-text: #FFFFFF;

  /* Border radius */
  --cometchat-radius-2: 8px;
  --cometchat-radius-3: 12px;

  /* Border colors */
  --cometchat-border-color-light: #E0E0E0;
}
```

### Available CSS Variables

| Variable                                           | Purpose                 | Default           |
| -------------------------------------------------- | ----------------------- | ----------------- |
| `--cometchat-spacing-1` to `--cometchat-spacing-4` | Padding, margin, gap    | `4px` to `16px`   |
| `--cometchat-font-heading4-medium`                 | Title font              | `500 16px Roboto` |
| `--cometchat-font-body-regular`                    | Subtitle font           | `400 14px Roboto` |
| `--cometchat-font-button-medium`                   | Button text font        | `500 14px Roboto` |
| `--cometchat-background-color-01`                  | Bubble background       | `#FFFFFF`         |
| `--cometchat-background-color-02`                  | Body section background | `#F5F5F5`         |
| `--cometchat-text-color-primary`                   | Title color             | `#141414`         |
| `--cometchat-text-color-secondary`                 | Subtitle color          | `#666666`         |
| `--cometchat-primary-button-background`            | Button background       | `#6852D6`         |
| `--cometchat-primary-button-text`                  | Button text color       | `#FFFFFF`         |
| `--cometchat-radius-2`                             | Border radius           | `8px`             |
| `--cometchat-border-color-light`                   | Border color            | `#E0E0E0`         |

### Custom Color Schemes

```css expandable theme={null}
/* Blue theme */
.theme-blue cometchat-collaborative-document-bubble {
  --cometchat-primary-button-background: #1976D2;
  --cometchat-primary-color: #1976D2;
}

/* Green theme */
.theme-green cometchat-collaborative-document-bubble {
  --cometchat-primary-button-background: #4CAF50;
  --cometchat-primary-color: #4CAF50;
}

/* Dark theme */
[data-theme="dark"] cometchat-collaborative-document-bubble {
  --cometchat-background-color-01: #1E1E1E;
  --cometchat-background-color-02: #2C2C2C;
  --cometchat-text-color-primary: #FFFFFF;
  --cometchat-text-color-secondary: #B0B0B0;
  --cometchat-border-color-light: #404040;
}
```

### Custom Button Styling

```css expandable theme={null}
/* Custom button styling */
::ng-deep .cometchat-collaborative-document-bubble__button {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 20px;
  padding: 10px 20px;
  font-weight: 600;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s, box-shadow 0.2s;
}

::ng-deep .cometchat-collaborative-document-bubble__button:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
```

## Accessibility

The Collaborative Document Bubble component is fully accessible and follows WCAG 2.1 Level AA guidelines.

### WCAG 2.1 Compliance

* ✅ **1.1.1 Non-text Content (Level A)**: Banner image has empty alt attribute (decorative)
* ✅ **1.3.1 Info and Relationships (Level A)**: Proper semantic structure with button element
* ✅ **2.1.1 Keyboard (Level A)**: All functionality available via keyboard
* ✅ **2.4.7 Focus Visible (Level AA)**: Clear focus indicators on action button
* ✅ **4.1.2 Name, Role, Value (Level A)**: Action button has accessible name via aria-label

### Keyboard Support

| Key           | Action                    | Context                          |
| ------------- | ------------------------- | -------------------------------- |
| `Tab`         | Navigate to action button | When component is in focus order |
| `Shift + Tab` | Navigate backwards        | When button is focused           |
| `Enter`       | Activate button           | When button is focused           |
| `Space`       | Activate button           | When button is focused           |

### ARIA Attributes

| Attribute    | Element       | Value                 | Purpose                   |
| ------------ | ------------- | --------------------- | ------------------------- |
| `aria-label` | Action button | Localized button text | Provides accessible name  |
| `alt`        | Banner image  | Empty string          | Marks image as decorative |

### Screen Reader Behavior

Screen readers announce the component with:

1. **Banner image**: Skipped (decorative)
2. **Title**: "Collaborative Document" (or localized equivalent)
3. **Subtitle**: "Open document to edit content together" (or localized equivalent)
4. **Button**: "Open Document, button" (or localized equivalent)

## Best Practices

<Tip>
  Always provide the complete CometChat.CustomMessage object to ensure the document URL is correctly extracted from metadata.
</Tip>

<Warning>
  The component expects the document URL at `metadata["@injected"]["extensions"]["document"]["document_url"]`. Ensure your message objects have this structure.
</Warning>

<Info>
  Use the `alignment` property to distinguish between incoming and outgoing messages for proper visual styling.
</Info>

<Tip>
  Handle the `buttonClick` event if you need custom behavior beyond opening the URL in a new window.
</Tip>

<Warning>
  The action button is automatically disabled when the document URL is missing or empty.
</Warning>

<Info>
  The component automatically selects the appropriate banner image based on the current theme (light/dark).
</Info>

<Info>
  For troubleshooting tips, see the [Troubleshooting Guide](/ui-kit/angular/troubleshooting#cometchatcollaborativedocumentbubble).
</Info>

## Related Components

* **CometChatCollaborativeWhiteboardBubble**: Displays collaborative whiteboard messages
* **CometChatFileBubble**: Displays file attachment messages
* **CometChatMessageBubble**: Parent component for message bubbles
* **CometChatMessageList**: Displays lists of messages

## Technical Details

* **Standalone Component**: Can be imported and used independently
* **Change Detection**: Uses OnPush change detection strategy for optimal performance
* **Dependencies**:
  * Angular CommonModule
  * CometChat SDK for message types
  * TranslatePipe for localization
* **BEM CSS**: Follows Block Element Modifier naming convention
* **Accessibility**: WCAG 2.1 Level AA compliant
