Changelog
Versjonshistorikk for @navikt/lumi-survey.
Endringsloggen vedlikeholdes på engelsk i henhold til npm-konvensjoner.
All notable changes to @navikt/lumi-survey will be documented in this file.
This project follows SemVer.
[2.2.3] - 2026-09-13
Documentation
- Start with Surveyverksted to create and share a survey, then integrate the exported document in your app. The package README now follows this flow through backend setup and checking responses in Lumi.
- Add documentation, issue tracker and search keywords to the package metadata.
[2.2.2] - 2026-09-10
Distribution
- The package is now published to npmjs as the primary, anonymously readable registry and to GitHub Packages as a compatibility mirror. Consumers no longer need registry configuration or a GitHub token to install it.
- Published metadata now declares the MIT license and the package's source directory in
navikt/lumi.
[2.2.1] - 2026-09-07
Fixed
- V1 survey documents now ignore answers from hidden source questions when deciding which follow-ups to show, validate and submit. Closing a branch hides all dependent follow-ups while retaining their answers locally for returning to that branch. Alternative
anyconditions, metadata conditions and the existing behavior of negative conditions on visible, unanswered questions are preserved. Legacy flat survey visibility is unchanged. - Conditional page flows show the current step without an estimated percentage or fixed total. Linear flows retain their exact progress indicator.
[2.2.0] - 2026-08-31
Version 2.1.1 was prepared in the repository but never published. Its changes are included in 2.2.0 together with the later additions since 2.1.0.
Added
- Schema V2 submissions now include a versioned, canonical
visibleIfflow contract. Surveys that still use deprecated imperativelogicremain submission-compatible but deliberately omit the flow contract so analytics treats those rows as unpinned. LegacyvisibleIfshapes that cannot be represented exactly byvisible-if-v1likewise keep submitting without a flow contract instead of failing or recording false provenance.
Fixed
validateSurveyDocumentV1andbuildCanonicalSurveynow rejectvisibleIfoperators that cannot work against the referenced question's type — for exampleEQagainst a multiChoice question, whose array answers never strictly equal a single value. The error names the owning question, the referenced question and its type, and the operators that are allowed. The runtime-compatible set per type is exported asallowedVisibleIfOperators.CONTAINSremains supported for string-valued single-choice answers so existing code-authored V1 documents keep working; the workshop continues to offer exact equality for that type. METADATA conditions and legacy flat surveys are unaffected.Focus now follows dock transitions: opening targets the active heading, closing targets the minimized trigger, and successful submission targets the receipt heading. The minimized trigger no longer references an unmounted panel through disclosure attributes.
Consent storage no longer leaves the widget blank for five seconds when the Nav decorator is unavailable. The initial view is released after a 300 ms grace period while a late persisted dismissal can still be applied.
Rating questions now expose exactly one named group to assistive technology. The prompt is the fieldset legend (a level 3 heading when visible), the fieldset itself carries
role="radiogroup", and the visually hidden legend copy no longer duplicates an external prompt heading. Screen readers previously announced the question up to three times per rating group.The published stylesheet now contains only
lumi--namespaced selectors. Unused CSS Module output previously leaked generic selectors such as.container,.header,.paneland.activeinto consumer applications.Star-rating icons now keep a stable pointer target while hover and focus feedback changes. In Chromium, swapping the icon element during a real pointer interaction could leave the star focused but unchecked, so a required star question could not be submitted.
Text answers that exceed the configured limit, or the API maximum of 2000 characters, are now blocked in the widget with a field-level validation message instead of failing permanently as a generic transport error. Consumers can customize the new validation summary and length message with
labels.validationSummaryandlabels.textTooLong.Inline
eventsobjects no longer count parent re-renders as new dock views or restart the success auto-close timer.Dismissal storage failures now invoke
onDismissalPersistFailedwith their cause, while intentionalnonestorage and server rendering remain silent.
Internal
- The local full-chain verification now exercises every stable survey and field scenario from the test bench and records per-scenario receipts in the release evidence.
[2.1.0] - 2026-08-20
Added
createRatingSurveyDocumentandDEFAULT_RATING_SURVEY_DOCUMENTmake the page-based model the recommended starting point for rating surveys too.createDiscoverySurveyDocument,createTopTasksSurveyDocumentandcreateTaskPrioritySurveyDocumentprovide verified, page-basedSurveyDocumentV1templates for Lumi's specialized analytics.- Specialized survey contracts are checked by the widget before transport so invalid field IDs or answer shapes cannot silently produce empty analytics.
Fixed
- Specialized fields must now be required and always visible, Task Priority enforces a usable selection limit, optional answers are validated when supplied, and checkbox choices enforce
maxSelectionsin the UI as well as at submission. - Submission setup errors now settle the widget in its error state and call
onSubmitErrorinstead of leaving the UI in a permanent submitting state. - The new Discovery, Top Tasks and Task Priority document builders use one canonical field vocabulary:
task,success,blockerandpriority. The widget and API continue to accept the field IDs emitted by the deprecated 2.0.1 builders. Specialized analytics require an explicittype, so ordinary surveys with similarly named fields are never misclassified. - Multi-choice
maxSelectionsis now part of the V2 definition contract and is enforced by the API. Existing definitions without the field are enriched once on their first compatible submission; later limit changes are rejected as structural changes.
Documentation
- The legacy flat
LumiSurveyConfig, rating presets and builders are marked deprecated in TypeScript while remaining runtime-compatible in 2.x. - The package README now teaches
SurveyDocumentV1as the only model for new surveys and links to the page, visibility and migration guides. Legacy flat configs, presets, builders andlogicremain supported in 2.x but are documented only as compatibility APIs. - The
LumiSurveyDockexample now uses a consumer-definedsurveyvariable instead of the nonexistentNAV_STANDARD_RATINGsymbol.
[2.0.1] - 2026-08-20
Fixed
- Rating questions now render validation messages with Aksel's
ErrorMessagein a permanently mounted, polite live region. This gives rating, text and choice fields the same visual treatment and announcement priority. Rating errors previously used a plainBodyShortwith an assertive alert and a package-owned colour override. - Rating choices now form one keyboard tab stop. Arrow keys move and select within emoji, thumbs, stars and NPS controls, including wrapping from the first choice to the last and back.
[2.0.0] - 2026-08-19
This release adds the page-based authoring format (SurveyDocumentV1) — the serializable document Surveyverksted produces. A consumer on 1.0.0 cannot type-check or render an authored export at all, because the format did not exist there.
BREAKING
question.visibleIfis now typedVisibleIfCondition(leaf | group) so it can carryany/allgroups. Code that readsvisibleIf.operatordirectly must narrow withisConditionGroup/isLeafConditionfirst. Authoring a condition is unchanged — only reading one back is affected.LogicConditionstays leaf-only, soLogicRuleconsumers are untouched. (#333)
The dock title renders at the same size as in 1.0.0. Its line height tightens, and the description below it grows from 14px to 16px. See Changed.
Added
SurveyDocumentV1gains optional survey-level screens:intro(title,body?,startLabel?) andsuccess(title,body?) as plain strings.LumiSurveyDockderives its intro/success screens from the document, with explicit embed props as field-level overrides — a partialsuccess=keeps the authored title and body. Blank titles read as absent (lenient drafts never render an empty screen), and blankstartLabelfalls back to"Start"so the intro button always has an accessible name.validateSurveyDocumentV1shape-checks the new fields. (#441)behavior.initialPageId,behavior.simulatedViewportandstyle.panelMaxHeightadd an embedding seam for authoring previews: start the flow on a specific authored page, size and classify (viewport/deviceType) from a simulated viewport, and constrain the open panel's height. Production behavior is unchanged when the props are absent. (#338)validateSurveyDocumentV1exposes the widget's runtime document validation as a pure public seam for authoring tools before preview or export. (#338)SurveyDocumentV1,SurveyPageV1andSurveyQuestionV1add a serializable page-based authoring format. A page can contain multiple questions that render and validate together;singlePagepreserves page headings while step layout navigates pages. The new format uses question-levelvisibleIfand deliberately rejects legacylogic. Existing flatLumiSurveyConfiginputs remain supported unchanged. (#336)visibleIfnow supportsany(OR) andall(AND) to combine multiple conditions. The wider condition type is exported asVisibleIfCondition(withisConditionGroup/getLeafConditions/isLeafConditionhelpers);LogicConditionstays leaf-only soLogicRuleconsumers are unaffected. Note:question.visibleIfis now typedVisibleIfCondition(leaf | group), so code readingvisibleIf.operatordirectly must first narrow withisConditionGroup/isLeafCondition. (#333)
Changed
behavior.initialPageIdnow also suppresses the intro screen when the requested page exists in the document — an explicit start page (authoring previews, deep links) outranks the intro. A typo'd or unknown id keeps the intro and falls back to normal navigation. (#441)createTopTasksSurveynow expresses its flow withvisibleIfinstead oflogic. Answer-based value conditions (EQ/NEQ/GT/LT/CONTAINS) automatically enable step mode underquestionLayout: "auto", whileEXISTS-only progressive disclosure remains single-page. (#359)behavior.showProgress: truenow shows progress from the first question in step mode. Intro and success screens are not counted, and single-step surveys omit the indicator. Branching exposes only the known step number to assistive technology. (#334)Progress indicators now include visible step text:
Steg X av Nfor linear surveys andSteg Xwhen branching makes the total uncertain. (#418)Dock header typography now comes from Aksel
Heading/BodyShortprops instead offont-sizeoverrides in the package stylesheet. Upgrading from 1.0.0 does not change the rendered header size: 1.0.0 asked forHeading mediumbut the package's own unlayered rule overrode it to 1.25rem, so the header rendered at 20px/600 then and renders at 20px/600 now. Two smaller things do change: the heading's line height tightens from 32px to 28px, and the panel description grows from 14px to 16px, because it too came from a stylesheet override (--ax-font-size-small) and now usesBodyShort size="small"— which is 16px in Aksel's scale, not 14px. The header is the panel's title block and keeps one scale whatever fills it — an authored page title, the first question standing in for one, intro or success. (#416, #447)An authored page title now renders at the title scale with a visible group boundary above its questions. It previously shared the field scale with the question headings and labels below it (Aksel
Heading xsmalland.aksel-labelare both 1.125rem/bold), so a title, the question under it and the next field label were three identical lines. Applies both in the panel header and inline insinglePagelayout. New in this release — the page format itself did not exist in 1.0.0. (#447)
Fixed
- Step navigation now moves focus to the newly rendered question heading after both Next and Back, without stealing focus when an answer changes. (#417)
logicconditions that reference another question viacondition.questionIdare now evaluated against that question's answer instead of the current question's. Cross-question branching (e.g. routing on an earlier answer) now works the same wayvisibleIfalready did. (#332)- Submissions now omit answers from questions hidden by
visibleIfat submit time while retaining the complete survey definition. Hidden answers remain in local state so they are restored if the user reopens the branch. (#357) - Reachable-step estimates now count overlapping unresolved
visibleIfbranches (such as multipleNEQ/CONTAINSconditions or overlapping numeric ranges) together while still counting mutually exclusive branches only once. (#358) METADATAconditions now receive auto-collected context fields (deviceType,viewport,screenResolution,userAgent) and opt-in location fields in addition to flattenedcontext.tags. Submission-time visibility uses the same metadata map;context.debugremains excluded. (#144)
[1.0.0] - 2026-06-24
This release switches the widget to the v2 submission schema. The widget now always emits schemaVersion: 2; the v1 wire format is no longer sent. Requires a backend that accepts schema v2 (@navikt/lumi-api with schema v2 support, shipped in #297).
Changed
- BREAKING: Submissions are now sent with
schemaVersion: 2— the widget no longer emits the v1 payload shape (#297) - Each submission now carries a self-describing
definitionblock (SubmissionDefinitionwith typedfields:RATING,TEXT,SINGLE_CHOICE,MULTI_CHOICE,DATE), so the survey structure travels with the data
Added
deduplicationKeyon every submission for idempotent delivery: generated client-side, exposed viagetDeduplicationKeyfromuseLumiSurvey, and rotated after a successful submit and on reset- New public types re-exported from the package:
LumiApiFeedbackSubmission(theV1 | V2union),LumiApiFeedbackSubmissionV2,LumiApiSubmissionDefinition, andLumiApiSubmissionFieldDefinition
Internal
- Migrated the workspace from npm to pnpm (#210) and upgraded to TypeScript 6 (#238)
- Removed unused close-button CSS from the dock fallback styles (#269)
[0.4.0] - 2026-03-25
Added
- Multi-signal device detection: uses UA Client Hints, UA string parsing, and iPadOS 13+ heuristic (
maxTouchPoints) before falling back to viewport width (Closes #168) screenResolutionfield in submission context — captures actual screen dimensions viawindow.screen
Changed
deviceTypeclassification is now based on actual device signals instead of viewport width alone, fixing misclassification when browser DevTools is open
[0.3.0] - 2026-03-20
Added
hasIntroprop onProgressProps— shows progress bar from step 0 when survey has intro page
Fixed
- Progress bar no longer jumps/oscillates with chained
visibleIfconditions (Closes #163) - Progress bar now reaches 100% on the last step in branching surveys
- Progress bar only updates on navigation events, preventing visual jitter from checkbox interactions
Changed
- Replaced high-water mark mechanism with direct reachability estimation via
computeReachableStepsalgorithm
[0.2.0] - 2026-03-17
Added
- Added optional
introsupport toLumiSurveyDock, so surveys can start with an intro screen before the first question. - Added
behavior.showProgressandevents.onStepChangefor step-based surveys, including progress feedback based on visible steps. - Added
DEFAULT_SURVEY_THUMBS,DEFAULT_SURVEY_STARS, andDEFAULT_SURVEY_NPSexports for ready-made rating surveys.
Changed
useLumiSurvey().validate()andsubmit()now accept an optional question subset, so step-based and branched flows can validate only the questions in the active path.
Fixed
- Step navigation now respects
visibleIfconditions when moving through branched surveys. - Removed the horizontal scrollbar on emoji rating rows and improved smiley alignment.
[0.1.1] - 2026-03-05
Changed
- localStorage key prefix changed from
flexjar-*tolumi-*. Previously dismissed surveys will reappear once as the old keys are no longer read. Requireslumi-*to be allowlisted in the NAV consent API.
Removed
- Removed all legacy
flexjarreferences from source, mocks, and documentation. - Removed duplicate test file
FlexJarDock.test.tsx(covered byLumiSurveyDock.test.tsx).
[0.1.0] - 2026-02-26
Changed
- Removed
@navikt/nav-dekoratoren-modulerdependency. Theconsentstorage strategy now reads directly from the NAV consent API window globals (window.__DECORATOR_DATA__andwindow.webStorageController). No extra npm package needed — behavior is identical. - Simplified consent API polling logic (setInterval instead of recursive setTimeout).
- Cleaned up Storybook config (removed module aliasing and viteFinal override).
[0.0.5] - 2026-01-21
Changed
- Tooling: upgraded to Vitest v4 and added V8 coverage provider support (
@vitest/coverage-v8).
[0.0.4] - 2026-01-21
Fixed
- Next.js/SSR safety: LumiSurveyDock is a client component and avoids
window is not definedduring server rendering.
[0.0.3] - 2026-01-21
Changed
- Rating surveys: the first rating question defaults to
required: truewhen omitted. - Submit UX: button stays hidden until the user has interacted (validation happens on submit).
- Optional labeling: “(valgfritt)” is derived from
requiredconsistently; presets no longer hardcode it in prompt strings.
[0.0.2] - 2026-01-21
Added
- Runtime validation for invalid question references (visibility/branching).
- NPS hover/focus styling (moved to dedicated NPS styles).
Changed
- Privacy-safe defaults:
urlis never auto-collected;pathnameis only auto-collected whenbehavior.collectLocationis enabled. - Personal data notice is only shown when a text question is actually visible.
- Submit UX: submit button is hidden until submission is possible (no disabled “send” button).
- Logic conditions:
fielddefaults to"ANSWER"when omitted.
Removed
- Deprecated
createLumiApiTransport()export.
[0.0.1] - 2026-01-19
Added
- First installable edition
Changed
- Made
@navikt/lumi-surveyself-contained for external publishing.
