Upgrade to v2
v2 of the React SDK is in beta. This page tracks what you have to change when moving from v1. The client API is unchanged so far; the breaking changes to date are in the component layer, where the SDK is moving onto the design system, and in the translation layer, which moved to the runtime shared with Stream Chat.
Install the beta
v2 publishes to the beta npm tag. v1 keeps latest, so an unpinned install stays on v1.
yarn add @stream-io/video-react-sdk@betaQuick migration checklist
- Install the beta and build. Client, call and state APIs need no changes.
- Replace
TextButtonwithButton, andIconButton'senabledprop withactive. - Replace
variant="success",variant="danger"andvariant="active". - Search your CSS for the removed
str-video__button classes and the eight--str-video__composite-button__button-group*variables. - Re-check any spacing you derived from
--str-video__spacing-*: the scale shifted. - Look at your call controls on screen. Sizing changed even where your code did not.
- If you translated the SDK, re-key your dictionaries and rename
translationsOverridestotranslations. This one fails silently - see below. - Replace
<CallStats />. It is no longer exported - build the panel you need fromuseCallStatsReport(). - Change
StreamTheme'sthemefrom a class name to"light"or"dark", and move embedded CSS variable overrides fromthemetostyle. Both fail silently - see below.
The button family is now one component
Before v2 there were three unrelated components: .str-video__button was a full-width
CTA, IconButton rendered a bare padded icon with no background or state, and only
CompositeButton produced the round call-control pill.
They are now one token-driven primitive. .str-video__button carries the pill,
IconButton is its icon-only shape, and CompositeButton composes it into a call control
with an optional caption and split menu. Button is exported for the first time.
Renamed and removed
| Removed | Replacement |
|---|---|
TextButton |
Button |
IconButtonWithMenuProps |
CompositeButtonProps |
IconButton prop enabled |
active |
variant="success" | "danger" | "active" |
"destructive", or the active prop |
variant now maps to the design system's Style and appearance to its Type. active
renders as aria-pressed, so a selected control is exposed to assistive technology
rather than only styled.
Removed CSS classes
str-video__text-button, str-video__button__icon, str-video__call-controls__button*,
str-video__composite-button__button* and str-video__menu-toggle-button* are gone.
They are replaced by str-video__button--* and
str-video__composite-button__{group,action,caret}.
Removed theming variables
The eight --str-video__composite-button__button-group* hooks are gone. Buttons are
themed through the design tokens now.
Spacing was re-based
--str-video__spacing-* keep their names but every step shifted:
| Token | v1 | v2 |
|---|---|---|
xs |
6px | 8px |
sm |
8px | 12px |
md |
12px | 16px |
lg |
16px | 20px |
xl |
20px | 24px |
If you used these tokens for your own layout, it moves with them. Icon-only button insets
also changed (at lg, from 8px to 16px), so a button sized around its own padding is now
a different size.
Translations moved to a shared runtime
The SDK now uses @stream-io/i18n, the
translation runtime shared with Stream Chat, and translation keys are namespaced
identifiers instead of the English text:
t("Mute all"); // v1
t("participantList.muteAll.label", "Mute all"); // v2The second argument is the English copy, written at the call site. That is why the SDK no
longer ships an en.json or a translations export: a key missing from your dictionary
renders that inline English rather than a raw key.
If you never touched i18n, there is nothing to do. English is unchanged - every string renders exactly as it did in v1.
If you did translate the SDK
Re-keying is not optional, and it fails quietly. An old key never matches, so your override
silently stops applying and the SDK's English renders instead - no error, no warning,
nothing in the console. Type your dictionaries as TranslationDictionary to turn that into
a compile error.
| Removed | Replacement |
|---|---|
translationsOverrides |
translations - registers over the defaults instead of replacing |
fallbackLanguage |
removed - use i18nextConfigOverrides: { fallbackLng } |
StreamI18n |
Streami18n - different class, different options |
StreamI18nProvider |
removed - StreamVideo mounts the translation context |
TranslationsMap |
Record<string, LooseTranslationDictionary> |
TranslationLanguage, TranslatorFunction |
removed - use string and StreamTFunction |
the translations export, en.json |
removed - English is inline at each call site |
useI18n().i18n |
removed - useI18n() returns { t, tDateTimeParser } |
The old-to-new key mapping is published as
i18n-2.0-key-map.json
in the SDK repository. Most rows are a straight rename; a handful are not, and those carry
a note explaining what to do.
Note that translationsOverrides replaced the SDK's dictionary in v1 rather than
merging with it, so supplying one German string dropped the rest. If you worked around that
by spreading the SDK's translations.en back into yours, delete the spread - translations
merges, and a partial dictionary is safe.
The i18n guide covers the new API in full.
CallStats was removed
The prebuilt CallStats panel is no longer part of the SDK. The data behind it is
unchanged: useCallStatsReport() still emits a full report every two seconds, and
call.setStatsReportingIntervalInMs() still controls the cadence.
| Removed | Replacement |
|---|---|
CallStats |
Your own panel, built on useCallStatsReport() |
The Call Statistics recipe rebuilds the panel v1 shipped - the same stats, the same latency and jitter thresholds, and the bitrate derivation the component did internally - so a v1 panel can be restored by copying it in.
CallStatsButton is unaffected. It toggles whichever panel you render; it no longer has a
panel of its own to toggle.
theme is now "light" or "dark"
StreamTheme's theme prop used to take a CSS class name, with "str-video__theme-dark"
as the default. It now takes "light" or "dark", still defaulting to dark, and renders
str-video__theme-light or str-video__theme-dark itself.
EmbeddedCall and EmbeddedLivestream take the same "light" or "dark" value in their
theme prop. The CSS variable overrides that theme used to accept move to a new style
prop.
| v1 | v2 |
|---|---|
<StreamTheme theme="str-video__theme-dark"> |
<StreamTheme theme="dark">, or omit it |
<StreamTheme theme=""> (light) |
<StreamTheme theme="light"> |
<EmbeddedCall theme={{ "--str-video__…": "…" }} /> |
<EmbeddedCall style={{ "--str-video__…": "…" }} /> |
| - | <EmbeddedCall theme="light" /> |
A class name passed to theme no longer matches any theme: it renders as
str-video__theme-<your value>, so the UI silently falls back to the light tokens. A CSS
variable object passed to the embedded theme is ignored in the same way. TypeScript
flags both; plain JavaScript does not.
The Theme page covers the new props.
What to expect during the beta
The design-token migration is proceeding component by component, so more changes of this shape are coming. Treat this page as the running list and re-read it when you bump; each entry will name the version it landed in and the change you have to make.
If you hit something that behaves differently and is not listed here, that is worth reporting: an unlisted break is a bug in this page as much as in the SDK.
Staying on v1
v1 is maintained on its own release line and stays on the latest tag. If you are not
ready to move, pin @stream-io/video-react-sdk@latest and switch this page to v1 with the
version picker above.