Opportunities Widget – React SDK

Install the Opportunities Widget as an NPM package for first-class React (and TypeScript) support.

Installation

npm install @legionhandtech/lht-react-widgets

React 17+ is a peer dependency. If your project already has React installed you're good to go.

Quick Start

1import { LegionOpportunities } from "@legionhandtech/lht-react-widgets"; 2 3function App() { 4 return ( 5 <LegionOpportunities 6 baseUrl="https://your-legion-domain.com" 7 count={5} 8 layout="horizontal" 9 theme="light" 10 tags="retail,food" 11 /> 12 ); 13}

Props Reference

Core Props

PropTypeDefaultDescription
baseUrlstringrequiredBase URL of your Legion deployment
countnumber5Number of opportunities to display (1–20)
layout"horizontal" | "vertical""horizontal"Layout direction
variant"portrait" | "square" | "banner" | "list" | "hero"autoCard style (portrait for horizontal, list for vertical)
tagsstringComma-separated list of tags to filter by
theme"light" | "dark" | "minimal" | "bold" | "corporate" | "vibrant""light"Preset theme
heightstring"auto"Widget height — "auto", "100%", or a CSS value like "400px"
apiKeystringOptional API key for authenticated content
classNamestringCSS class applied to the outer container
styleReact.CSSPropertiesInline styles merged into the container
onLoad(detail) => voidCalled when the widget iframe finishes loading
onError(message: string) => voidCalled if the widget iframe fails to load

Theming Props

All theming props are optional. When omitted the widget uses its built-in defaults.

The card system keeps text off the image: the photo lives in a fixed-ratio frame and copy sits on a solid surface. The legacy overlay-panel props (oppPanelStart, oppPanelBlur, …) and shadow props were removed with the card revamp.

Card Surface

PropCSS VariableExample
oppAccent--opp-accent"#5a48e6"
oppAccentContrast--opp-accent-contrast"#ffffff"
oppCardBg--opp-card-bg"#ffffff"
oppTextColor--opp-text-color"#16181d"
oppCardRadius--opp-card-radius"18px"
oppCardShadow--opp-card-shadow"0 4px 12px rgba(0,0,0,.1)"
oppCardHoverShadow--opp-card-hover-shadow"0 8px 24px rgba(0,0,0,.15)"
oppCardBorder--opp-card-border"1px solid #e6e8ec"
oppFontFamily--opp-font-family"Inter, sans-serif"

Media Frame & Chips

PropCSS VariableExample
oppMediaRatio--opp-media-ratio"5 / 4"
oppMediaBg--opp-media-bg"#dfe2e7"
oppCategoryBg--opp-category-bg"rgba(16,18,24,.5)"
oppCategoryColor--opp-category-color"#ffffff"
oppRewardBg--opp-reward-bg"#fdeecb"
oppRewardColor--opp-reward-color"#8a5a00"
oppRewardSize--opp-reward-size"12.5px"

Title Typography

PropCSS VariableExample
oppTitleSize--opp-title-size"19px"
oppTitleColor--opp-title-color"#16181d"
oppTitleWeight--opp-title-weight"700"
oppTitleFontFamily--opp-title-font-family"Inter, sans-serif"

Description Typography

PropCSS VariableExample
oppDescriptionSize--opp-description-size"13.5px"
oppDescriptionColor--opp-description-color"#626a78"
oppDescriptionFontFamily--opp-description-font-family"Inter, sans-serif"
oppDescriptionLineHeight--opp-description-line-height"1.45"

Expires Typography

PropCSS VariableExample
oppExpiresSize--opp-expires-size"12.5px"
oppExpiresColor--opp-expires-color"#8b93a1"

Buttons

PropCSS VariableExample
oppButtonRadius--opp-button-radius"12px"
oppSaveBorder--opp-save-border"#e0e3e8"
oppSaveBg--opp-save-bg"transparent"
oppSaveColor--opp-save-color"#626a78"

Animation

PropCSS VariableExample
oppTransitionDuration--opp-transition-duration"0.3s"

Preset Themes

Use the theme prop for quick preset styling instead of individual theming props:

ThemeDescription
lightDefault — white surface, dark accent button
darkDark card surface with light text
minimalBorder-only cards, no shadows
boldLarger titles, rounder corners
corporateSlate accent, sharp corners, no animations
vibrantIndigo accent with colored hover glow
1<LegionOpportunities 2 baseUrl="https://your-legion-domain.com" 3 theme="dark" 4 count={5} 5/>

Imperative Ref API

Use a React ref to call methods on the widget:

1import { useRef } from "react"; 2import { 3 LegionOpportunities, 4 LegionOpportunitiesHandle, 5} from "@legionhandtech/lht-react-widgets"; 6 7function App() { 8 const widgetRef = useRef<LegionOpportunitiesHandle>(null); 9 10 return ( 11 <> 12 <button onClick={() => widgetRef.current?.refresh()}> 13 Refresh Widget 14 </button> 15 <LegionOpportunities 16 ref={widgetRef} 17 baseUrl="https://your-legion-domain.com" 18 /> 19 </> 20 ); 21}

Available Methods

MethodDescription
refresh()Reloads the widget iframe

Web Component (from NPM)

If you prefer the <legion-opportunities> custom element but want to install via NPM instead of a script tag:

import "@legionhandtech/lht-react-widgets/web-component";

Then use it in your HTML or JSX:

1<legion-opportunities 2 base-url="https://your-legion-domain.com" 3 count="5" 4 layout="horizontal" 5 theme="light" 6> 7</legion-opportunities>

TypeScript

The package ships with full TypeScript declarations. All prop interfaces are exported:

1import type { 2 OpportunitiesWidgetProps, 3 OpportunitiesThemingProps, 4 LegionOpportunitiesHandle, 5} from "@legionhandtech/lht-react-widgets";

Callbacks

onLoad

Fired when the widget iframe has loaded. Receives a detail object:

1<LegionOpportunities 2 baseUrl="https://your-legion-domain.com" 3 onLoad={(detail) => { 4 console.log(detail.widget); // "opportunities" 5 console.log(detail.count); // number 6 console.log(detail.layout); // "horizontal" | "vertical" 7 console.log(detail.tags); // string 8 }} 9/>

onError

Fired if the widget iframe fails to load:

1<LegionOpportunities 2 baseUrl="https://your-legion-domain.com" 3 onError={(message) => console.error(message)} 4/>
Documentation | Legion Hand Technologies