@truconsent/consent-notice
v0.0.41
Published
React consent-notice components (in-page & modal)
Readme
@truconsent/consent-notice
React components for embedding truConsent consent banners and the Data Principal Rights Center into any web application.
Current version: 0.0.41
Changelog
0.0.41
- Fixed
Reject Allincorrectly triggering the H-Case "Consent Required" warning popup whenever any mandatory purpose was configured (the common case) —rejectAll()built a synthetic all-declined purposes array and ran it through the same mandatory-decline interceptsavePreferences/"I Consent" uses, which always found the mandatory purpose "declined" in that array and blocked the action. Reject All is a deliberate, explicit decline of everything (mandatory included); it no longer runs through the intercept at all - Fixed
HCaseWarningPopup(the "Consent Required" popup) rendering with fixed white background, black title, and grey message text regardless of the notice's configured theme — now falls back to the same--banner-bg/--banner-text/--banner-text-muted/--banner-button-color/--banner-button-text-color/--banner-hover-bgCSS variables the rest of the modal already uses, so it always matches the configured background/text/button colors. Admin-configuredh_case_*color overrides still take priority when set - Fixed the same popup's proceed button silently using the modal's Background Color as its own background whenever
h_case_proceed_button_colorwasn't explicitly configured — the fallback chain readprimaryColor(which resolves to Background Color, not Button Color, despite the prop's name) before ever reaching the Button Color CSS variable; reordered so Button Color wins - Fixed the Tabbed Notice's
Next/Okbutton always using white text regardless of the configured Button Text Color — the button's background correctly read Button Color, but its text color was hardcoded via CSS (.tru-btn-primary { color: #fff; }) and never readbuttonTextColor, unlike every other action button
0.0.40
- Rights Center: nominee verification before a submitted/updated nominee is treated as active — OTP (via the backend's
/nominee/{id}/send-otp+/verify-otp, MSG91) with DigiLocker shown as a disabled "Coming Soon" option. A nominee stays in a "Not verified yet" state with a Verify Now action until OTP verification succeeds - Fixed the nominee verify modal not rendering (hooks declaration-order bug), only appearing while the Grievance tab was active (should be visible regardless of active tab), and losing the widget's
--banner-*theme variables when rendered via adocument.bodyportal — now renders inline so it inherits the scoped theme - Resized the modal (560px → 460px max-width) and stopped leaking internal request paths/HTTP status codes in error messages
0.0.39
- Increased the General Notice header's logo (
ModernBannerHeader.jsx) fromh-7(28px) toh-10(40px) — too small to clearly identify the brand at the previous size, per user report on the "Consent by Mars Money" banner. Keptw-autoso non-square logos aren't distorted
0.0.38
- Fixed
I Consentstaying enabled (and clickable) even when the user switched a Necessary/mandatory purpose's toggle off. Necessary toggles stay interactive by design — the user can still switch one off — but doing so must disable the "I Consent" action itself; only Reject All / Only Necessary remain available at that point, matching the existing H-Case warning popup's own definition of "mandatory purpose declined"
0.0.37
- Fixed
I Consentbeing disabled whenever every optional purpose was declined, requiring at least one optional acceptance on top of the normal scroll-gating — Reject All and Only Necessary never had this extra requirement. Optional purposes are the user's free choice to accept or decline;Only Necessaryalready exists as the dedicated "decline everything optional" action, so gatingI Consenton an optional acceptance just made it redundant withOnly Necessaryand confusingly disabled in the all-declined state - Fixed the Tabbed Notice's Informational/Consent tab
Next/Okbutton using Background Color (primaryColor) for its own background — every other action button already used the configured Button Color; this one alone used the modal's background color instead, giving it no real background in most themes - Fixed the Tabbed Notice's Consent tab purpose groups rendering in
Necessary → Optional → Profile Basedorder — nowNecessary → Profile Based → Optional, matching the configured display priority
0.0.36
- Changed the Tabbed Notice's active tab label and underline to use Primary Text Color (
--banner-text) instead of Button Color — this partially reverses 0.0.32's change (Button Color was picked there to fix a different case where the tab was invisible against a matching background). Button Color is chosen for contrast against a button's own background, not the banner's background, so a light banner paired with a bright accent Button Color (e.g. lime green on white) read as low-contrast for body text. Primary Text Color is guaranteed legible against the banner's own background by definition. This exact change is now the reference truKIT-react-native and truKIT-flutter-sdk mirror
0.0.35
- Fixed the General Notice's purpose-card toggle switch rendering the wrong track/thumb colors (a fixed dark "success" green track,
--banner-bgthumb) whenever the Cookie Banner's CSS was also loaded on the same page. Both widgets' toggles used the same generic.switch/.track/.thumbclass names, butTruCookieConsent's Cookie Banner styling (.switch input:checked+.track, specificity 0,3,1) is more specific than the General Notice's own rule (input:checked+.track, 0,2,1) and silently won regardless of which widget was actually on screen — any site loading bothconsent-modal.cssandbanner-styles.csstogether (the normal case) was affected. Renamed the General Notice's toggle classes to.tru-switch/.tru-track/.tru-thumbacrossModernPurposeCard.jsx,CompactListUI.jsx,SplitPaneUI.jsx, andInlineSingleRowUI.jsxto remove the collision entirely - Fixed the Tabbed Notice's tab buttons showing the browser's raw default focus ring (a solid blue rounded outline in Chrome/Edge, unrelated to the widget's theme) on click/focus, which looked like a stray highlight box obscuring the tab label — replaced with a theme-colored
:focus-visibleoutline
0.0.34
- Fixed
TruConsentModal'sstyleVarsnever setting--banner-border/--banner-hover-bgat all — every purpose card border and the header/footer wrapper background fell through tovariables.css's fixed light-theme preset (#e5e7eb) regardless of configuration, showing as a bright near-white border on any dark-configured banner. Both now derive from the configured Primary Text Color, matching the pattern already used inTruCookieConsent.jsx - Fixed the "Necessary" badge never appearing on a mandatory purpose card in
BannerUI.jsx(never passedshowNecessaryTagat all) and only appearing for the narrowerisDynamic && isMandatorycondition inTabbedBannerUI.jsx— any genuinely mandatory but non-dynamic purpose showed no indication at all that it was required. Both (andPreferencesModalUI.jsx, which had the same gap) now show the badge for every mandatory purpose, matching truKIT-react-native/truKIT-flutter-sdk's existingisMandatory-only condition
0.0.33
- Fixed the purpose-toggle switch's thumb (
.thumbin the Notice,.rc-slider:beforein the Rights Center,.tp-thumbin the Cookie Consent Manage Preferences panel) using the configured Primary Text Color instead of the Primary Button Text Color — the thumb sits on a colored track, not on the card's own background, so it needs to read against the button's text/background pairing, not the body text color. Also fixed.tp-thumb's unchecked (off) state still hardcoding#fff— its checked state already read the CSS var correctly, but the base rule never did, so the two states could visibly disagree - This exact corrected behavior (thumb = Primary Button Text Color, same whether on or off) is now the reference truKIT-react-native and truKIT-flutter-sdk mirror
0.0.32
- Fixed
TruConsentModal's card/close-button border (--banner-border) andTruCookieConsent's cookie banner + Manage Preferences panel border (--banner-border/--tp-border) never being derived from the configured theme — both fell through to a hardcoded light-theme gray that looked like a stray white border on a dark card; now derived from the configured secondary/body text color (matchingRightCenter.jsx's existinghexToRgba(secondaryText, 0.45)pattern), also fixing--banner-hover-bgthe same way - Fixed the tabbed Notice's active tab label always using the neutral text color instead of the configured Button Color — text and underline now both use the accent color together
- Fixed the cookie consent Manage Preferences panel (
#tp-modal) hardcoding a fixed system-font stack, ignoring the configured Font Type entirely - Fixed the Manage Preferences "Strictly Necessary" category card's left accent border hardcoding a fixed green (
#10b981) instead of the configured Button Color, unlike every other (non-essential) category card, which already correctly used it - Fixed the Manage Preferences category toggle's thumb (inner circle) hardcoding white regardless of state — the track already correctly used the configured Button Color when on, but the thumb never reflected the configured Button Text Color
- Added the missing
side_panelGeneral Notice template — selecting "Side Panel" in the admin's Templates picker previously silently rendered as Center Modal, since no component was ever registered for that key (the CSS positioning for the drawer-from-the-right-edge layout already existed and just needed a component to fill it) - Fixed the purpose-toggle switch (
.thumb/.trackin the Notice,.rc-slider/.rc-slider:beforein the Rights Center) never actually using the configured Button Color for the "on" track or the configured Primary Text Color for the thumb — both were hardcoded (a fixed "success" green token for the Notice's on-track, literalwhite/hardcoded gray for the Rights Center's thumb/off-track) regardless of what's configured. The thumb is now the same color (Primary Text Color) whether on or off — only the track's color changes to signal state — and this exact behavior is now the reference truKIT-react-native and truKIT-flutter-sdk mirror
0.0.31
- Fixed
--banner-bgreading nonexistentbackgroundColor/cardBackgroundfields (0.0.30 checked for fields that don't exist anywhere in the API response) — it now readssettings.primaryColor, the actual field the admin dashboard's "Background Color" setting maps to, so the configured background color renders instead of always falling through to the hardcoded white default
0.0.30
- Fixed
TruConsentModalnot reading dashboard theme colors when the API returns athemeobject instead ofbannerSettings/banner_settings(added a bridging mapper so colors from the real API response are no longer silently dropped to JS defaults) - Fixed
--banner-bgnever being set from the configured background color, soBannerUIand othergeneral_consenttemplates always rendered the CSS default background regardless of dashboard configuration
Install
npm install @truconsent/consent-noticeComponents
<ConsentModal /> — Consent Banner
Renders the truConsent consent notice (banner/modal) for a given collection point.
import { ConsentModal } from '@truconsent/consent-notice';
import '@truconsent/consent-notice/dist/consent-modal.css';
<ConsentModal
userId="user-uuid"
apiKey={import.meta.env.VITE_TRU_CONSENT_API_KEY}
organizationId={import.meta.env.VITE_TRU_CONSENT_ORGANIZATION_ID}
apiUrl={import.meta.env.VITE_TRU_CONSENT_API_URL}
assetId={import.meta.env.VITE_TRU_CONSENT_ASSET_ID}
bannerId={import.meta.env.VITE_TRU_CONSENT_BANNER_ID}
/><RightCenter /> — Data Principal Rights Center
Pre-built UI for DPDPA data subject rights — consent management, data access/deletion requests, grievances, nominees, and DPO info.
Single asset
import { RightCenter } from '@truconsent/consent-notice';
import '@truconsent/consent-notice/dist/consent-modal.css';
<RightCenter
userId="user-uuid"
apiKey={import.meta.env.VITE_TRU_CONSENT_API_KEY}
organizationId={import.meta.env.VITE_TRU_CONSENT_ORGANIZATION_ID}
apiUrl={import.meta.env.VITE_TRU_CONSENT_API_URL}
assetId={import.meta.env.VITE_TRU_CONSENT_ASSET_ID}
/>Multiple assets via groupId
Use groupId to load consents from all assets in a group into one unified view:
<RightCenter
userId="user-uuid"
apiKey={import.meta.env.VITE_TRU_CONSENT_API_KEY}
organizationId={import.meta.env.VITE_TRU_CONSENT_ORGANIZATION_ID}
apiUrl={import.meta.env.VITE_TRU_CONSENT_API_URL}
groupId={import.meta.env.VITE_TRU_CONSENT_GROUP_ID}
/>Props
| Prop | Type | Required | Description |
|---|---|---|---|
| userId | string | ✅ | Authenticated user ID — must match the ID used when consent was recorded |
| apiKey | string | ✅ | Consent-scope API key from the platform dashboard |
| organizationId | string | ✅ | Org ID sent as X-Org-Id on every request |
| apiUrl | string | ✅ | SDK base URL e.g. https://trukit-dev.truconsent.io |
| assetId | string | one of | Asset UUID. Use for a single-asset setup |
| groupId | string | one of | Asset group UUID. Loads consents across all assets in the group. Takes precedence over assetId |
| authToken | string | — | Bearer token for JWT-authenticated tenants |
Pass at least one of
assetIdorgroupId. When both are provided,groupIdwins.
Consent card behaviour
- Legitimate Interest purposes →
Legitimate Interestbadge (green) +Shown: Yes/No— no toggle - Mandatory purposes →
Necessarybadge (red) +Consented: Yes/No— no toggle - Optional purposes → no badge +
Consented: Yes/No+ toggle to withdraw/grant consent Showntimestamp is sourced exclusively from the server consent log (shown_at) set when the banner was displayed to the user
Environment variables
VITE_TRU_CONSENT_API_KEY=your_api_key
VITE_TRU_CONSENT_ORGANIZATION_ID=your_org_id
VITE_TRU_CONSENT_API_URL=https://trukit-dev.truconsent.io
VITE_TRU_CONSENT_ASSET_ID=your_asset_uuid
VITE_TRU_CONSENT_GROUP_ID=your_group_uuid # optional — for multi-asset Rights Center
VITE_TRU_CONSENT_BANNER_ID=your_banner_uuid # for ConsentModalDevelopment
# Install dependencies
npm install
# Build the package
npm run build
# Run tests
npm testBuild outputs to dist/. CSS files are copied from src/styles/ directly.
Changelog
0.0.29
- Fixed: Primary Text Color / Secondary Text Color had no visible effect on the Notice modal (
<TruConsentModal />), across every template (Center Modal, Tabbed Banner, Notice Only).ModernBannerHeader.jsx/ModernPurposeCard.jsx/SplitPaneUI.jsx/etc. all readcolor: var(--banner-text)/var(--banner-text-muted)with no fallback default — butTruConsentModal.jsx's own rootstyleVars, andBannerUI.jsx's,TabbedBannerUI.jsx's, andNoticeOnlyBanner.jsx's own template-levelstyleVars, never actually set those two CSS variables anywhere, even thoughprimaryTextColor/secondaryTextColorwere already being fetched correctly from the API. With nothing in the cascade ever defining them, elements using them (tab labels, purpose titles/descriptions, category badges) fell back to the browser's own initial value instead of the configured color — this is what caused labels like the "Consent" tab and "OPTIONAL" badge to render unreadable against the modal's actual background. All four files now set--banner-text: primaryTextColor/--banner-text-muted: secondaryTextColor(falling back to#111827/#6b7280) alongside the primary/secondary color variables they already set. - Fixed: the active "Consent"/"Cookies" tab in the Tabbed Banner template (
TabbedBannerUI.jsx) rendered its label and underline invar(--banner-primary-color), which for the Notice API is the Notice's Background Color field — on any asset with a light/near-white background color, the active tab's own text and underline were nearly invisible against the same-toned modal.consent-modal.css's.tru-tab-button[data-active]underline now usesvar(--banner-button-color, var(--banner-primary-color))(the actual accent color) as the active-state indicator, while the tab's text color staysvar(--banner-text)— the same primary text color used by every other heading/label in the modal (e.g. the "Consent by [Organization Name]" title) — since an active tab is a label, not a button, and shouldn't switch to the button's accent color.
0.0.28
- Fixed: on the Cookie Banner specifically, Button Text Color, Font Type, and Font Size never had any effect no matter what was set in Global Settings —
apps/api/backend's/api/v1/internal/sdk/cookie-consentendpoint's theme response never includedbutton_text_color/font_type/font_sizeat all (unlike the Notice and Rights Center endpoints, which already merged these from the sameappearance_global_settingsrow). Background color and the accept/reject button background colors worked because those fields were already wired — only the three now-added fields were missing. - Fixed the widget side to match:
TruCookieConsent.jsxnever set--font-sizeas a CSS variable at all for the Cookie Banner (so the existingcalc(var(--font-size, 16px) * ratio)rules always silently fell back to the 16px default), hardcoded its font-family stack ignoring Font Type, and hardcoded the primary/accept button's text color to white regardless of the Button Text Color setting (both the summary bar's Accept button and the preferences modal's Save Preferences button).
0.0.27
- Fixed: the appearance "Font Size" setting had no effect anywhere in
<RightCenter />—--font-sizewas never even set as a CSS variable, so all 62font-sizerules inRightCenter.csswere hardcoded pixel values. Every rule now scales offcalc(var(--font-size, 16px) * ratio), preserving the existing visual hierarchy while responding to the setting. - Fixed the same gap in the Cookie Banner (
banner-styles.css,TruCookieConsent.jsx) and Notice modal (consent-modal.css,TruConsentModal.jsx): only the outermost container picked upfont-sizeviavar(--font-size, inherit), but every button, button-label, and secondary/description text rule used arem(root-relative) unit that ignored it entirely — converted to the samecalc(var(--font-size, 16px) * ratio)pattern. Decorative icon glyphs and fixed micro-badges were left as-is deliberately. - Backend fix (not a widget change, but required for this to actually take effect):
apps/api/backend's/rights-center/settings/globalendpoint had a response-construction path — the common "asset already has settings saved" case — that never merged in the asset's real appearance row at all, silently falling back to the response schema's hardcoded defaults for every color and font field, not justfont_size. - Redesigned the Non-SSO phone/OTP modal: combined the country code into a single fixed "+91" prefix on the mobile number field (no longer a separate editable input), added a close button, a "we'll text a 6-digit code" helper line, and a verification-trust footer note.
- Redesigned the Non-SSO OTP verification screen: replaced the single free-text OTP field with a 6-box segmented digit input (auto-advance on type, backspace-to-previous, paste support), added a "Code sent to +91 xxxxxxxxxx Change" line (Change returns to the phone step), and combined the previously stacked "Back" button and resend control into one footer row.
- Fixed: the modal's close (×) button did nothing on either the phone or OTP step — there was no dismiss state at all. Both close buttons now actually hide the modal and restore page scroll.
- Fixed: the "Change"/"Resend" links rendered in a fixed violet/purple color instead of the widget's configured button/primary theme color — they now use the same
var(--banner-primary-color)as every other themed control. - Fixed a variable-ordering bug where the modal's dismissed-state check ran before the state itself was declared, silently no-opping the close button regardless of theme/build target.
- Fixed: the Non-SSO "Consents You Have Given" list was showing mandatory ("Necessary") purposes even when their recorded value was "declined" — mandatory purposes have no opt-in concept (DPDPA doesn't require consent for them) and their default/untouched value could get bundled into any real log for that collection point, making it look like the data principal had "given" a consent they never actually acted on. The list now only includes purposes with a genuine affirmative record (accepted for optional purposes, actually-shown for Legitimate Interest); mandatory purposes with a real log are now shown separately under a new "Mandatory Processing (No Consent Required)" section.
- Fixed: a purpose could be silently dropped from the Non-SSO "Consents You Have Given" list even when it had a real "shown" disclosure record — this happened whenever a purpose's current
is_legitimateflag disagreed with its ownpurpose_type(a real data inconsistency:purpose_type='legitimate_optional'butis_legitimate=false), which made the widget treat it as an "optional" purpose and checkconsented === 'accepted'instead of the "shown" signal that Legitimate Interest disclosures actually record. The list (and the individual consent card's Shown/Consented badge) now checks the recorded "shown" status directly instead of trusting only the (possibly stale)is_legitimateflag. - Fixed: the Non-SSO modal is
position: fixed, but the host page's body remained scrollable behind it — the modal now locksdocument.bodyscroll while open and restores it on close/resolution. - Added
line-heightto the modal's hint/description text, which previously used the browser default and could look oddly spaced when it wrapped to two lines.
0.0.26
- Non-SSO (mobile + OTP) access for
<RightCenter />: when an asset'saccess_modeisnon_ssoand nouserIdprop is supplied, the widget renders a phone-entry + OTP-verification modal (with resend + cooldown) instead of the tab UI, resolving adata_principal_idonce verified - Non-SSO consent view is read-only and scoped to purposes with an actual recorded decision for that phone number only — no toggle/save capability, no full-purpose-catalog exposure (distinct from the SSO give/withdraw experience)
- When
access_modeissso(default) and nouserIdis supplied, renders an explanatory "please log in" message instead of a silently broken tab UI - Fixed: consent save grouped purposes by asset instead of by collection point, so toggling a purpose from any collection point other than the first-seen one for that asset silently sent zero save requests despite showing "Changes Saved"
0.0.25
groupIdprop on<RightCenter />— load consents across all assets in an asset group- Consent card 4-column layout: name / badge / expiry period / toggle — pixel-aligned across all rows
- Badge logic: Legitimate Interest (green outlined), Necessary (red solid), no badge for optional
- Shown/Consented split: LI purposes show
Shown: Yes/Noonly; non-LI showConsented: Yes/Noonly shown_attimestamp sourced only from server consent logs (banner-display event); generic timestamp fallbacks removed- Banner shown → all LI purposes in that banner automatically marked as
shown_to_principal = true
0.0.24
- Rights Center UI alignment and layout improvements
0.0.23
- Initial Rights Center (
<RightCenter />) release
License
MIT
