Skip to content

Sidebar Plugins ​

What it does ​

A sidebar plugin renders as a compact card in the right sidebar of a server. Multiple sidebar plugins stack vertically. The card is always visible (when the sidebar is open) alongside the channel's message area.

When to use this context ​

Use sidebar plugins for:

  • Live stats: server activity, member count, online users
  • Countdowns: event timers, deployment schedules
  • Quick widgets: weather, time zone, leaderboards
  • Glanceable information: no click-through required

Sidebar plugins should be lightweight and non-intrusive. Avoid long scrolling content.

Minimal example ​

html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="https://app.dissent.chat/sdk/v1/dissent-plugin-sdk.iife.js"></script>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
      font-family: system-ui, sans-serif;
      background: transparent;
      color: rgba(255,255,255,0.85);
      padding: 12px;
    }
    .widget {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 16px;
    }
    .label {
      font-size: 12px;
      color: rgba(255,255,255,0.5);
      text-transform: uppercase;
      letter-spacing: 0.5px;
      font-weight: 600;
    }
    .value {
      font-size: 20px;
      font-weight: 800;
      font-variant-numeric: tabular-nums;
    }
  </style>
</head>
<body>
  <div class="widget">
    <div>
      <div class="label">Event starts in</div>
      <div class="value" id="countdown">--:--:--</div>
    </div>
  </div>
  <script>
    function formatCountdown(ms) {
      if (ms <= 0) return 'Live!';
      const totalSeconds = Math.floor(ms / 1000);
      const hours = Math.floor(totalSeconds / 3600);
      const minutes = Math.floor((totalSeconds % 3600) / 60);
      const seconds = totalSeconds % 60;
      return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
    }

    async function main() {
      const ctx = await Dissent.init({
        onFallback: () => {
          document.getElementById('countdown').textContent = 'Not in Dissent';
        },
      });

      // Apply theme
      for (const [k, v] of Object.entries(ctx.theme)) {
        document.documentElement.style.setProperty(k, v);
      }

      // Parse event time from config
      const eventTime = ctx.config.eventTime ? new Date(ctx.config.eventTime).getTime() : Date.now() + 3600000;

      // Update countdown every second
      setInterval(() => {
        const now = Date.now();
        const ms = eventTime - now;
        document.getElementById('countdown').textContent = formatCountdown(ms);
      }, 1000);

      // Sync theme on change
      Dissent.on('theme:change', (theme) => {
        for (const [k, v] of Object.entries(theme)) {
          document.documentElement.style.setProperty(k, v);
        }
      });
    }

    main().catch(err => console.error(err));
  </script>
</body>
</html>

Gotchas ​

  • Keep height compact. Sidebar cards don't scroll. Stay under 200px in height for best UX.
  • Multiple plugins stack vertically. Don't assume you're the only sidebar plugin. Keep your card self-contained.
  • background: transparent looks better than solid background. Let the app's theme show through.
  • ctx.channel may be undefined. In sidebar context, the user might not have a channel selected. Always guard: if (ctx.channel?.id) { /* ... */ }.