Bridge Training
Bridge React

Usage

How to integrate and use @workspace/bridge-react in your application.

Installation

Add the dependency to your app's package.json:

{
  "dependencies": {
    "@workspace/bridge-react": "workspace:*"
  }
}

Peer Dependencies

The package requires React and react-i18next as peer dependencies:

{
  "peerDependencies": {
    "react": "^19",
    "react-dom": "^19",
    "react-i18next": "^15"
  }
}

Import Styles

Import the package stylesheet in your app's root CSS:

globals.css
@import "@workspace/bridge-react/styles.css";

Provider Setup

Global Provider

Wrap your application with BridgeProvider to configure the engine for all child components:

import { BridgeProvider } from '@workspace/bridge-react/bridge-context/bridge-provider';

function App() {
  return (
    <BridgeProvider context={{ teachingMode: 'auction', locale: 'fr' }}>
      {/* All bridge components use this engine */}
    </BridgeProvider>
  );
}

The context prop accepts a BridgeContext object (see Bridge Core Usage for details).

Without a Provider

All components work without a provider. When no BridgeProvider is in the tree, useBridgeEngine() falls back to a default engine with the classic variant:

import { SuitDisplay } from '@workspace/bridge-react/suit/suit-display';

// Works without any provider — uses classic variant defaults
function Standalone() {
  return <SuitDisplay suit="S" />;
}

Per-Component Override

Every exported component that uses the engine internally is wrapped with withBridgeContext. This adds an optional context prop that creates a local provider, overriding any parent provider:

import { BridgeProvider } from '@workspace/bridge-react/bridge-context/bridge-provider';
import { SuitDisplay } from '@workspace/bridge-react/suit/suit-display';

function App() {
  return (
    <BridgeProvider context={{ teachingMode: 'auction', locale: 'fr' }}>
      {/* Uses the global provider (classic variant, French notation) */}
      <SuitDisplay suit="S" />

      {/* Overrides with petit-bridge variant for this component */}
      <SuitDisplay suit="S" context={{ teachingMode: 'petit-bridge' }} />
    </BridgeProvider>
  );
}

This is useful for preview elements that need a different variant or locale than the rest of the app.

Components

Display Components

Simple components for rendering bridge entities:

import { SuitDisplay } from '@workspace/bridge-react/suit/suit-display';
import { CardDisplay } from '@workspace/bridge-react/card/card-display';
import { BidDisplay } from '@workspace/bridge-react/bid/bid-display';

<SuitDisplay suit="S" />
<SuitDisplay suit="H" colorVariant="bid" />

<CardDisplay card="SA" />

<BidDisplay bid="2H" />

Hand Component

The standalone Hand component renders a full bridge hand with inputs:

import { Hand } from '@workspace/bridge-react/components/hand/hand';

<Hand
  player="N"
  cards={{ S: ['A', 'K'], H: ['Q', 'J'], D: ['10', '9'], C: ['8'] }}
  readOnly
/>

Hand Compound Component

For more control, use the compound component API:

import { Hand } from '@workspace/bridge-react/hand/hand';

const SUITS = ['S', 'H', 'D', 'C'] as const;

<Hand.Root player="N" cards={cards} onCardsChange={handleChange}>
  {SUITS.map(suit => (
    <Hand.InputRow key={suit} suit={suit} value={cards[suit]} />
  ))}
</Hand.Root>

BiddingTable Compound Component

import { BiddingTable } from '@workspace/bridge-react/bidding/table/bidding-table';

<BiddingTable.Root dealer="N" vulnerability="ALL">
  <BiddingTable.Table>
    <BiddingTable.Header />
    <BiddingTable.Content>
      {rows.map((row, i) => (
        <BiddingTable.Row key={i}>
          {row.map((cell, j) =>
            cell ? (
              <BiddingTable.BidCell key={cell.index} bid={cell.bid} />
            ) : (
              <BiddingTable.EmptyCell key={j} />
            )
          )}
        </BiddingTable.Row>
      ))}
    </BiddingTable.Content>
  </BiddingTable.Table>
</BiddingTable.Root>

Form Components

Pre-built form fields for bridge settings:

import { VulnerabilitySelect } from '@workspace/bridge-react/form/vulnerability-select';
import { ScoringSelect } from '@workspace/bridge-react/form/scoring-select';

<VulnerabilitySelect value={vulnerability} onChange={setVulnerability} />
<ScoringSelect value={scoring} onChange={setScoring} />

BridgePrimitivesProvider

For apps that use the rich text editor, BridgePrimitivesProvider combines the engine context with the final comment editor context, and exposes an imperative ref:

import {
  BridgePrimitivesProvider,
  type BridgePrimitivesRef,
} from '@workspace/bridge-react/provider';
import { useRef } from 'react';

function Editor() {
  const ref = useRef<BridgePrimitivesRef>(null);

  const handleSave = () => {
    const html = ref.current?.getFinalCommentHTML();
    const pbn = ref.current?.getFinalCommentPBN();
  };

  return (
    <BridgePrimitivesProvider
      ref={ref}
      context={{ teachingMode: 'auction', locale: 'fr' }}
    >
      {/* Editor components */}
    </BridgePrimitivesProvider>
  );
}

Internationalization (i18n)

Components that display text (form labels, player names, etc.) use translations from the primitives namespace via react-i18next.

The package exports its translation resources for integration into your app's i18next setup:

import { primitivesResources, PRIMITIVES_NAMESPACES } from '@workspace/bridge-react/i18n';

For detailed loading strategies (HTTP backend vs direct bundle), see the i18n Usage documentation.

Quick Setup

import { primitivesResources } from '@workspace/bridge-react/i18n';

i18n.init({
  ns: ['translation', 'primitives', 'rich-editor'],
  resources: {
    en: { translation: appEn, ...primitivesResources.en },
    fr: { translation: appFr, ...primitivesResources.fr },
  },
});

On this page