Right-Side Panel Positioning with UxPortal

How to position a panel/sidebar on the right edge using UxPortal

Right-Side Panel Positioning with UxPortal

Challenge

Position a properties panel on the far right edge of the screen using UxPortalService, maintaining fixed positioning and full viewport height.

Solution: Component-Level Positioning

The UxPortal service's positioning configuration doesn't directly apply styles to the component content. Instead, apply positioning directly to the component's root element.

Implementation

1. Component SCSS (Direct Positioning)

.properties-panel {
  position: fixed !important;  // Override any portal styles
  top: 0 !important;
  right: 0 !important;          // Pin to right edge
  width: 320px;
  height: 100vh;               // Full viewport height
  z-index: 10000;              // Above other content
  
  background: rgba(255, 255, 255, 0.98);
  backdrop-filter: blur(12px);
  border-left: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: 
    -10px 0 25px rgba(0, 0, 0, 0.15),
    -6px 0 12px rgba(0, 0, 0, 0.1);
}

2. Portal Configuration (Minimal)

private openPortal() {
  const config: UxPortalConfig = {
    id: this.portalId,
    reusePortal: true,
    content: {
      type: 'component',
      data: PropertiesPanelContentComponent,
      context: { component: this }
    },
    container: {
      mode: 'overlay',
      pointerEvents: 'none',  // Host doesn't block clicks
      closeOnOutsideClick: false,
      closeOnEscape: false,
      constrainToViewport: false
    },
    backdrop: {
      type: 'none',
      enabled: false
    },
    styling: {
      theme: 'custom',
      customClass: 'properties-panel-portal-host'
    },
    animation: {
      entrance: 'slide-right',
      exit: 'slide-right',
      duration: 200
    }
  };

  this.portalService.openPortal(config);
}

3. Prevent Infinite Loop

private isPortalOpen = false;

constructor() {
  effect(() => {
    const mod = this._module();
    if (mod && !this.isPortalOpen) {
      this.openPortal();
    } else if (!mod && this.isPortalOpen) {
      this.closePortal();
    }
  });
}

private openPortal() {
  if (this.isPortalOpen) return;
  this.isPortalOpen = true;
  // ... open portal
}

private closePortal() {
  if (!this.isPortalOpen) return;
  this.isPortalOpen = false;
  this.portalService.closePortal(this.portalId);
}

Key Takeaways

  1. Component controls positioning - Use !important in component SCSS for fixed positioning
  2. Portal handles rendering - Use portal for overlay management and animations
  3. Guard against loops - Use flag to prevent repeated open/close calls
  4. Host transparency - Set pointerEvents: 'none' on host so only content receives clicks

Result

✅ Panel appears at right edge
✅ Full viewport height
✅ Smooth slide animations
✅ No infinite loop issues
✅ Proper z-index layering