Skip to main content

Default UI

As of version 0.3.0, the SDK auto-mounts a polished session-controls widget on sdk.initialize(). No extra code is required for the default experience. Every option is opt-in and fully customizable; existing callers of new SessionHeader().mount(element, ...) keep working unchanged.

Zero-Config Default

const sdk = new MarketplaceSDK({
applicationId: 'your-app-id',
apiKey: 'gwsk_YOUR_API_KEY_HERE',
jwksUri: 'https://api.generalwisdom.com/.well-known/jwks.json',
});
await sdk.initialize();
// A floating session-controls widget appears at bottom-right with timer
// and Extend button.
new MarketplaceSDK({
applicationId: 'your-app-id',
apiKey: 'gwsk_YOUR_API_KEY_HERE',
sessionControls: {
// Six-way viewport positioning
position: 'top-right', // 'top-left' | 'top-center' | 'top-right'
// 'bottom-left' | 'bottom-center' | 'bottom-right' (default)
offset: { x: 24, y: 24 }, // pixels from the anchored edge

// Idle fade: never applies at/below warning threshold (correctness invariant)
fade: {
enabled: true, // default true
idleOpacity: 0.7, // default 0.7
idleDelayMs: 5000, // default 5000
},

// Timer + buttons
timerFormat: 'countdown', // 'countdown' | 'elapsed' | 'both'
showExtendButton: true, // default true

// Developer links — up to 2 primary links render inline; rest fold into an overflow menu
links: [
{ label: 'Support', href: 'https://example.com/support', primary: true },
{ label: 'Docs', href: 'https://example.com/docs' },
{ label: 'Terms', href: 'https://example.com/terms' },
],

// Themeable via theme tokens or --gw-sc-* CSS variables
theme: {
colors: { primary: '#FF6B35' },
borderRadius: 14,
},
zIndex: 2147483000,
},
});

Positioning

The widget supports six viewport positions arranged in a 2x3 grid:

┌──────────────────────────────────────────────┐
│ top-left top-center top-right │
│ │
│ │
│ (your app) │
│ │
│ │
│ bottom-left bottom-center bottom-right │
└──────────────────────────────────────────────┘

Default: bottom-right

Set via the position property in sessionControls:

sessionControls: {
position: 'top-right', // or any of the 6 positions
offset: { x: 24, y: 24 }, // optional pixel offset from edge
}

On viewports narrower than 480px, the widget collapses to a full-width bar anchored to the top or bottom edge. See Narrow Viewport Behavior below.

CSS Variables Reference

Every visual property of the widget is exposed as a CSS custom property on the .gw-session-controls root element. Override any of these in your stylesheet without writing JS:

VariableDefaultDescription
--gw-sc-bg#1a1f27Widget background
--gw-sc-primary#EFC139Primary accent (buttons, active states)
--gw-sc-secondary#8b949eSecondary text
--gw-sc-radius8pxBorder radius
--gw-sc-shadow0 4px 12px rgba(0,0,0,0.3)Box shadow
--gw-sc-padding12px 16pxInternal padding
--gw-sc-gap12pxGap between elements
/* Example: dark blue theme */
.gw-session-controls {
--gw-sc-bg: #0f172a;
--gw-sc-primary: #38bdf8;
--gw-sc-secondary: #94a3b8;
--gw-sc-radius: 12px;
--gw-sc-shadow: 0 8px 24px rgba(0,0,0,0.5);
}

Theme Customization

Pass theme overrides via the SDK constructor for programmatic control:

new MarketplaceSDK({
applicationId: 'your-app-id',
apiKey: 'gwsk_YOUR_API_KEY_HERE',
sessionControls: {
theme: {
colors: { primary: '#FF6B35' },
borderRadius: '12px',
},
},
});

You can also update the theme at runtime after initialization:

sdk.updateSessionControls({
theme: {
colors: { primary: '#22c55e' },
borderRadius: '16px',
},
});

Theme tokens set via the constructor or updateSessionControls() map directly to the CSS variables above, so both approaches produce identical visual results. Use CSS variables for static themes and the JS API when the theme depends on runtime state.

Opting Out

If your application has its own session UI, disable the default widget entirely:

new MarketplaceSDK({
applicationId: 'your-app-id',
apiKey: 'gwsk_YOUR_API_KEY_HERE',
sessionControls: { autoMount: false }, // nothing renders automatically
});

With autoMount: false:

  • No DOM elements are injected by the SDK
  • All lifecycle events (onSessionWarning, onSessionExtended, onSessionEnd) still fire
  • Timer data is still available via sdk.getTimer().getRemainingSeconds()
  • You retain full control over your custom UI

This is the right approach when:

  • You already have a bespoke session-controls component
  • You need the widget to render inside a specific container rather than floating
  • Your design system requires strict control over all rendered elements

For manual mounting into a specific container instead of floating, see Manual Mount / Update / Unmount below.

Manual Mount / Update / Unmount

sdk.mountSessionHeader({
mode: 'floating',
getTime: () => sdk.getFormattedTime(),
sdk,
position: 'top-right',
});

sdk.updateSessionControls({ position: 'bottom-center' });
sdk.unmountSessionHeader();

Theming via CSS Variables

Every visual property is a --gw-sc-* CSS custom property on the widget's root element. Override in your own stylesheet with no JS:

.gw-session-controls {
--gw-sc-bg: #1a1a1a;
--gw-sc-primary: #FF6B35;
--gw-sc-radius: 14px;
}

Stable Classnames

  • .gw-session-controls — root element
  • __timer — timer display
  • __extend — extend button
  • __link — link element
  • __overflow — overflow container
  • __menu — dropdown menu

State Modifiers

  • --idle — widget in idle state
  • --warning — approaching expiration
  • --critical — very low time remaining
  • --floating — floating position mode
  • --inline — inline position mode
  • --narrow — narrow viewport mode

Custom Timer Display

Build your own UI using SDK data:

const timer = sdk.getTimer();

setInterval(() => {
const remaining = timer.getRemainingSeconds();
const minutes = Math.floor(remaining / 60);
const seconds = remaining % 60;

document.getElementById('timer').textContent =
`${minutes}:${seconds.toString().padStart(2, '0')}`;

if (remaining < 300) {
document.getElementById('timer').classList.add('warning');
}
}, 1000);

Custom Styling

.gw-session-header {
background: #1a1a1a;
border-bottom: 2px solid #333;
padding: 12px 24px;
}

.gw-session-timer {
font-size: 18px;
font-weight: 600;
color: #00ff88;
}

.gw-session-timer--warning {
color: #ff6b00;
animation: pulse 1s infinite;
}

@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}

Narrow Viewport Behavior

Below 480px the widget collapses to a full-width edge bar on the configured top or bottom edge. Horizontal position is ignored at that width (all six positions collapse to full-width). If your mobile app has a bottom navigation bar, set position: 'top-*' to keep the bottom edge clear.

Warning Modal

Customize the warning UI:

onSessionWarning: async (context) => {
const modal = document.getElementById('warning-modal');
modal.style.display = 'block';

modal.querySelector('.minutes-remaining').textContent = context.minutesRemaining;

modal.querySelector('.extend-btn').onclick = async () => {
await sdk.extendSession(30);
modal.style.display = 'none';
};

modal.querySelector('.continue-btn').onclick = () => {
modal.style.display = 'none';
};
},
<div id="warning-modal" class="modal" style="display: none;">
<div class="modal-content">
<h2>Session Expiring Soon</h2>
<p>Your session will expire in <span class="minutes-remaining"></span> minutes.</p>
<div class="modal-buttons">
<button class="extend-btn">Extend Session (+30 min)</button>
<button class="continue-btn">Continue</button>
</div>
</div>
</div>

Backward Compatibility

new SessionHeader().mount(element, { position, sdk, onEnd }) is unchanged — existing SessionHeader tests still pass. If you were using this API, your code continues to work. To adopt the new widget, add sessionControls to SDKConfig or call sdk.mountSessionHeader(...) explicitly.


:::tip Try it live Experiment with position, idle-fade, and theme settings in real time on the SDK Playground. Changes apply instantly to a running session and generate copy-ready code snippets. :::