QRCode.js is a professional JavaScript/TypeScript library for creating customized QR codes, offering a blend of simplicity and sophistication. With versatile styling options—dot shapes, colors, gradients, embedded images, borders, and text—it enables you to design unique, visually appealing QR codes that work flawlessly with standard scanners. QRCode.js is part of QR-Platform: All-in-One QR Codes Management Solution.
This documentation provides an overview of all available options to help you create the perfect QR code for your needs.
# Using npm
npm install @qr-platform/qr-code.js
# Using yarn
yarn add @qr-platform/qr-code.js
# Using pnpm
pnpm add @qr-platform/qr-code.js
import { QRCodeJs } from '@qr-platform/qr-code.js';
// Create a basic QR code
const qrCode = new QRCodeJs({
data: 'https://example.com',
});
// Render the QR code to a container
qrCode.append(document.getElementById('qr-container'));
datastring'https://example.com'shapeShapeType enum'square''square', 'circle'shape: 'circle'
marginnumber0margin: 20
width and heightisResponsive is false, these values override the auto-calculated dimensions. When isResponsive is true, these values are ignored in favor of responsive sizing.number | string (optional)300, 500'300px', '20rem', '50vh', '100%'// Fixed pixel dimensions
width: 300,
height: 300
// CSS units
width: '20rem',
height: '20rem'
// Mixed units
width: 400,
height: '30vh'
isResponsivetrue, the SVG uses 100% width/height and ignores any specified width/height values. When false, the SVG uses specified width/height values or auto-calculated dimensions.booleanfalsetrue: SVG becomes fluid (100% width/height), any width/height values are ignoredfalse: SVG uses width/height values if provided, otherwise uses auto-calculated dimensions// Responsive QR code (ignores width/height)
isResponsive: true,
width: 500, // This will be ignored
height: 500 // This will be ignored
// Fixed size QR code (uses width/height)
isResponsive: false, // or omit (default)
width: 300,
height: 300
1. Fixed-Size QR Codes (Print, Downloads):
const qrCode = new QRCodeJs({
data: 'Fixed size for printing',
width: 300,
height: 300,
isResponsive: false // Default behavior
});
2. Responsive Web QR Codes:
const qrCode = new QRCodeJs({
data: 'Responsive for web',
isResponsive: true // Ignores width/height, uses container size
});
3. CSS Unit Dimensions:
const qrCode = new QRCodeJs({
data: 'Using CSS units',
width: '20rem',
height: '20rem'
});
qrOptionsOptions that affect the QR code generation algorithm.
typeNumberTypeNumber (0-40)0 (auto-determine based on content)qrOptions: {
typeNumber: 4
}
modeMode enum'numeric', 'alphanumeric', 'byte', 'kanji', 'unicode'qrOptions: {
mode: 'alphanumeric'
}
errorCorrectionLevelErrorCorrectionLevel enum'Q''L': Low - 7% error recovery'M': Medium - 15% error recovery'Q': Quality - 25% error recovery'H': High - 30% error recoveryqrOptions: {
errorCorrectionLevel: 'H'
}
Options controlling the positioning and scaling of the QR code within its container.
scalenumber (0 to 1.5)1scale: 0.8 // Make QR code 80% of available space
offsetnumber0offset: -10 // Move QR code 10px up
verticalOffsetnumber0verticalOffset: 5 // Move QR code 5px down
horizontalOffsetnumber0horizontalOffset: -5 // Move QR code 5px left
dotsOptions)Controls the appearance of individual QR code dots.
typeDotType enum'square''dot': Round dots'square': Square dots'rounded': Slightly rounded squares'extraRounded': More rounded squares'classy': Dots with a distinctive classy pattern'classyRounded': Classy dots with rounded corners'verticalLine': Vertical line pattern'horizontalLine': Horizontal line pattern'randomDot': Randomized dot pattern'smallSquare': Smaller square dots'tinySquare': Very small square dots'star': Star-shaped dots'plus': Plus-shaped dots'diamond': Diamond-shaped dotsdotsOptions: {
type: 'rounded'
}
colorstring (CSS color, hex, rgb, rgba)'#000000'dotsOptions: {
color: '#FF5733'
}
sizenumber10dotsOptions: {
size: 12
}
gradientGradient object (see Gradients)undefineddotsOptions: {
gradient: {
type: 'linear',
rotation: Math.PI / 4,
colorStops: [{ offset: 0, color: 'blue' }, { offset: 1, color: 'red' }]
}
}
cornersSquareOptions)These options override dotsOptions for the three large corner squares of the QR code.
typeCornerSquareType enumdotsOptions.type or uses 'dot''dot': Round corner squares'square': Square corner squares'rounded': Rounded corner squares'classy': Classy corner squares'outpoint': Corner squares with outward points'inpoint': Corner squares with inward pointscornersSquareOptions: {
type: 'outpoint'
}
colorstring (CSS color, hex, rgb, rgba)dotsOptions.color or uses '#000000'cornersSquareOptions: {
color: '#0000FF'
}
gradientdotsOptions.gradient)Gradient object (see Gradients)undefinedcornersSquareOptions: {
gradient: {
type: 'radial',
colorStops: [{ offset: 0, color: 'green' }, { offset: 1, color: 'yellow' }]
}
}
cornersDotOptions)These options override cornersSquareOptions for the smaller dots within the corner squares.
typeCornerDotType enumcornersSquareOptions.type or uses 'dot''dot': Round corner dots'square': Square corner dots'heart': Heart-shaped corner dots'rounded': Rounded corner dots'classy': Classy corner dots'outpoint': Corner dots with outward points'inpoint': Corner dots with inward pointscornersDotOptions: {
type: 'heart'
}
colorstring (CSS color, hex, rgb, rgba)cornersSquareOptions.color or uses '#000000'cornersDotOptions: {
color: '#FF0000'
}
gradientcornersSquareOptions.gradient)Gradient object (see Gradients)undefinedcornersDotOptions: {
gradient: {
type: 'linear',
rotation: 0,
colorStops: [{ offset: 0, color: 'orange' }, { offset: 1, color: 'purple' }]
}
}
backgroundOptions)Controls the QR code background.
object or false to disable the background{ color: '#FFFFFF' }colorstring (CSS color, hex, rgb, rgba)'#FFFFFF'backgroundOptions: {
color: '#F5F5F5'
}
roundnumber or string0backgroundOptions: {
round: 0.5
}
gradientGradient object (see Gradients)undefinedbackgroundOptions: {
gradient: {
type: 'linear',
rotation: Math.PI / 2,
colorStops: [{ offset: 0, color: '#eee' }, { offset: 1, color: '#ccc' }]
}
}
imageQRCodeJs.setImage() for a global default, or QRCodeJs.useImage() for a builder-specific image.string | Buffer | Blobimage: 'https://example.com/logo.png'
setImage and useImagesetImage and useImage methods can accept an optional second parameter with { override: true } to ensure the image takes precedence over any image set elsewhere.// Global image that will override any instance-specific images
QRCodeJs.setImage('https://example.com/global-logo.png', { override: true });
// Builder pattern with image that will override final options
const qr = QRCodeJs.useImage('https://example.com/important-logo.png', { override: true })
.options({
data: 'https://example.com',
image: 'https://example.com/this-will-be-ignored.png' // Will be ignored due to override
});
imageOptionsOptions for the embedded image.
modeImageMode enum'center''center': Image placed in the center, QR code dots reflow around it'overlay': Image placed on top of the QR code'background': Image used as a background with dots drawn over itimageOptions: {
mode: 'center'
}
imageSizenumber0.4imageOptions: {
imageSize: 0.5
}
marginnumber0imageOptions: {
margin: 2
}
crossOriginstringundefinedimageOptions: {
crossOrigin: 'anonymous'
}
fillobject{ color: 'rgba(255,255,255,1)' }color: A solid color fill (string)gradient: A gradient fill (Gradient object, see Gradients)imageOptions: {
fill: {
color: 'rgba(255,255,255,0.75)'
}
}
imageOptions: {
fill: {
gradient: {
type: 'radial',
colorStops: [{ offset: 0, color: 'rgba(255,255,255,1)' }, { offset: 1, color: 'rgba(255,255,255,0)' }]
}
}
}
Gradients can be applied to multiple elements: dotsOptions, cornersSquareOptions, cornersDotOptions, and backgroundOptions.
objecttype: Type of gradient ('linear' or 'radial')rotation: Rotation of gradient in radians (for linear gradients)colorStops: Array of color stop objects with offset (0-1) and color properties{
dotsOptions: {
gradient: {
type: 'linear',
rotation: Math.PI / 4, // 45 degrees
colorStops: [
{ offset: 0, color: '#8F00FF' }, // Start color
{ offset: 1, color: '#0080FF' } // End color
]
}
}
}
QRCode.js provides border features:
borderOptionsOptions for adding decorative borders around the QR code. Borders can be configured globally using QRCodeJs.setBorder() / QRCodeJs.setBorderId() or on a per-instance basis using the builder pattern initiated with QRCodeJs.useBorder() / QRCodeJs.useBorderId().
hasBorderbooleanborderOptions: {
hasBorder: true
}
thicknessnumberborderOptions: {
thickness: 50
}
colorstring (CSS color, hex, rgb, rgba)'#000000'borderOptions: {
color: 'blue'
}
radiusstring (px or %)'0%'borderOptions: {
radius: '40%'
}
noBorderThicknessnumberborderOptions.thickness / 4borderOptions: {
noBorderThickness: 5
}
backgroundstring (CSS color, hex, rgb, rgba)undefinedborderOptions: {
background: '#DDDDDD'
}
innerobjectradius: Corner rounding of the inner border (string)scale: Scale factor for the inner content (number, 0-1.5)horizontalOffset: Horizontal offset of the inner content (number)verticalOffset: Vertical offset of the inner content (number)borderOptions: {
inner: {
radius: '10%',
scale: 0.8,
horizontalOffset: -15,
verticalOffset: 10
}
}
borderOuterobjectcolor: Color of the outer border (string)thickness: Thickness of the outer border (number)borderOptions: {
borderOuter: {
color: '#002683',
thickness: 10
}
}
borderInnerobjectcolor: Color of the inner border (string)thickness: Thickness of the inner border (number)borderOptions: {
borderInner: {
color: 'yellow',
thickness: 5
}
}
decorationsobjecttop, right, bottom, left)borderOptions: {
decorations: {
top: {
disabled: false,
enableText: true,
offset: 0,
curveAdjustment: 0,
curveDisabled: false,
curveRadius: '50%',
type: 'text',
value: 'SCAN ME',
style: {
fontFace: 'Helvetica',
fontSize: 28,
fontColor: '#ffffff',
textTransform: 'uppercase',
letterSpacing: 2,
fontWeight: 'bold'
}
}
}
}
Each decoration object can have these properties:
disabled: Whether this side’s decoration is disabledenableText: Whether to enable text on this sideoffset: Positioning offset for the decorationcurveAdjustment: Adjustment for text curvecurveDisabled: Whether to disable curved textcurveRadius: Radius of the text curvetype: Type of decoration ('text' or 'image')value: Text content or image URLstyle: Style options for text (font, size, color, etc.)const qrCode = new QRCodeJs({
data: 'https://example.com',
borderOptions: {
hasBorder: true,
thickness: 40,
color: '#0033CC',
radius: '10%'
}
});
// Then create QR code with custom border text
const qrCode = new QRCodeJs({
data: 'https://example.com',
borderOptions: {
hasBorder: true,
thickness: 40,
color: '#0033CC',
radius: '10%',
decorations: {
bottom: {
enableText: true,
type: 'text',
value: 'Scan Me',
style: {
fontFace: 'Arial',
fontSize: 24,
fontColor: '#FFFFFF'
}
}
}
}
});
QRCode.js provides dedicated methods for managing text on QR code borders, allowing for convenient text configuration across all sides.
setText()function(textNameOrOptions: string | TextOptions | null, options?: { override?: boolean }): typeof QRCodeJstextNameOrOptions: A predefined text template name (e.g., ‘Scan Me (Top)’), a custom TextOptions object, or null to clearoptions: Optional configuration with override property to ensure text takes precedence// Set global text on top and bottom border sides
QRCodeJs.setText({
topValue: 'SCAN ME',
bottomValue: 'www.example.com'
});
// Use a predefined text template
QRCodeJs.setText('Scan Me (Top)');
// With override option to ensure it takes precedence
QRCodeJs.setText({ topValue: 'MUST DISPLAY THIS TEXT' }, { override: true });
// Clear global text
QRCodeJs.setText(null);
setTextId()function(textId: string | null, options?: { override?: boolean }): typeof QRCodeJstextId: ID of a predefined text template (e.g., ‘visit-website-bottom’) or null to clearoptions: Optional configuration with override property to ensure text takes precedence// Set global text using a predefined template ID
QRCodeJs.setTextId('scan-to-visit-website');
// With override option
QRCodeJs.setTextId('lost-found', { override: true });
// Clear global text
QRCodeJs.setTextId(null);
useText()function(textNameOrOptions: string | TextOptions, options?: { override?: boolean }): QRCodeBuildertextNameOrOptions: A predefined text template name or a custom TextOptions objectoptions: Optional configuration with override property to ensure text takes precedenceQRCodeBuilder instance for chaining// Start builder with custom text options
const qrCode = QRCodeJs.useText({
topValue: 'VISIT OUR WEBSITE',
bottomValue: 'www.example.com'
}).options({
data: 'https://example.com'
});
// Start builder with a predefined text template
const qrWithTemplate = QRCodeJs.useText('Scan Me (Bottom)')
.options({ data: 'https://example.com/scan-me' });
// With override option to ensure text takes precedence over final options
const qrWithOverride = QRCodeJs.useText(
{ leftValue: 'IMPORTANT TEXT' },
{ override: true }
).options({
data: 'https://example.com',
borderOptions: {
decorations: {
left: { value: 'This will be ignored', enableText: true }
}
}
});
useTextId()function(textId: string, options?: { override?: boolean }): QRCodeBuildertextId: ID of a predefined text template (e.g., ‘visit-website-bottom’)options: Optional configuration with override property to ensure text takes precedenceQRCodeBuilder instance for chaining// Start builder with a predefined text template by ID
const qrCode = QRCodeJs.useTextId('scan-to-visit-website')
.options({ data: 'https://example.com' });
// With override option
const qrWithOverride = QRCodeJs.useTextId('scan-me', { override: true })
.options({ data: 'https://example.com' });
The TextOptions object allows you to specify text for each side of the QR code border:
interface TextOptions {
topValue?: string | null; // Text for top border (null explicitly disables)
rightValue?: string | null; // Text for right border
bottomValue?: string | null; // Text for bottom border
leftValue?: string | null; // Text for left border
}
null explicitly disables text on that side'') will be treated as no text but with enableText: trueAll text methods accept an optional { override: true } parameter to ensure the text values take precedence over any text settings applied at a later stage:
setText() with override will override text from instance optionssetTextId() with override will override text from instance optionsuseText() with override will override text from final .options() calluseTextId() with override will override text from final .options() callThis is particularly useful when you need to ensure specific text appears regardless of other configuration.
// Set global default for all QR codes
QRCodeJs.setText({
topValue: 'SCAN ME',
bottomValue: 'www.example.com'
});
// Create QR code with custom border that uses the global text
const qrCode = new QRCodeJs({
data: 'https://example.com',
borderOptions: {
hasBorder: true,
thickness: 40,
color: '#0033CC',
radius: '10%'
// No decoration settings needed - will use the global text
}
});
// Chain builder methods for more complex setup
const qrChained = QRCodeJs.useBorder('Rounded Border (Large)')
.useText({
topValue: 'POWERED BY',
bottomValue: 'QR-PLATFORM'
})
.options({ data: 'https://example.com/chained' });
To remove text from borders:
// Clear global text settings
QRCodeJs.setText(null);
// Clear text on specific sides
QRCodeJs.setText({
topValue: null, // Explicitly remove top text
bottomValue: null, // Explicitly remove bottom text
});
// Use a predefined "empty" template to clear all sides
QRCodeJs.useText('empty-text-options').options({
data: 'https://example.com'
});
The QRCode.js library offers functionality to validate that generated QR codes are scannable.
validateScanning()Promise<ScanValidatorResponse> resolving to a validation result object ({ isValid: boolean, decodedText?: string, message?: string })const qrCode = new QRCodeJs({
data: 'https://example.com'
});
qrCode.validateScanning()
.then(result => {
if (result.isValid) {
console.log('QR code is valid and scannable!');
console.log('Decoded text:', result.decodedText);
} else {
console.log('QR code validation failed:', result.message);
}
});
QRCode.js can also be used in Node.js environments.
Follow the standard installation steps using npm or yarn.
import { QRCodeJs, Options } from '@qr-platform/qr-code.js/node'; // Import from '@qr-platform/qr-code.js/node'
import fs from 'fs';
const options: Options = {
data: 'https://example.com',
};
const qrCode = new QRCodeJs(options);
qrCode.serialize().then(svgString => {
if (svgString) {
fs.writeFileSync('qrcode.svg', svgString);
console.log('QR Code saved to qrcode.svg');
}
});
Import Path: Use import { QRCodeJs } from '@qr-platform/qr-code.js/node';.
Peer Dependencies: You must install the required peerDependencies for Node.js functionality.
Install automatically using npx:
npx i-peers @qr-platform/qr-code.js
Install manually using npm:
npm i @xmldom/xmldom @undecaf/zbar-wasm image-size jose jimp @resvg/resvg-js file-type
No Canvas/Download: Methods relying on browser APIs like append(), download(), or internal canvas generation are not available or behave differently in the Node.js version.
SettingsOptions, setSettings, useSettings)For a comprehensive way to define or apply a complete QR code configuration in one go, QRCode.js provides:
SettingsOptions interface to structure a full configuration.QRCodeJs.setSettings() method for establishing global defaults using a SettingsOptions object.useSettings() method for the QRCodeBuilder to apply a SettingsOptions object as a baseline for a specific builder chain.SettingsOptions ObjectThe SettingsOptions object allows you to define multiple aspects of a QR code configuration simultaneously:
id?: string: Optional unique identifier for the settings preset.name?: string: Optional descriptive name for the settings preset.description?: string: Optional detailed description of the settings preset.data?: string: The primary data to encode. This will be applied as the main data option.image?: string | Buffer | Blob: Image to embed. This will be applied as the main image option.template?: string | RecursivePartial<Options>: Template by name or options object. Maps to QRCodeJs.setTemplate() when used with QRCodeJs.setSettings().templateId?: string: Template by ID. Maps to QRCodeJs.setTemplateId().style?: string | StyleOptions: Style by name or StyleOptions object. Maps to QRCodeJs.setStyle().styleId?: string: Style by ID. Maps to QRCodeJs.setStyleId().text?: string | TextOptions: Text configuration by name or TextOptions object. Maps to QRCodeJs.setText().textId?: string: Text configuration by ID. Maps to QRCodeJs.setTextId().border?: string | RecursivePartial<BorderOptions>: Border configuration by name or options object. Maps to QRCodeJs.setBorder().borderId?: string: Border configuration by ID. Maps to QRCodeJs.setBorderId().options?: RecursivePartial<Options>: Direct overrides for any main Options properties. These are deeply merged. Maps to QRCodeJs.setOptions().Refer to the TypeScript Types and Definitions for the full structure.
QRCodeJs.setSettings()The QRCodeJs.setSettings(settings: SettingsOptions | null) static method sets multiple global defaults at once.
QRCodeJs.setTemplate(), QRCodeJs.setStyle(), QRCodeJs.setData(), QRCodeJs.setImage(), QRCodeJs.setOptions(), etc.) based on the properties provided in the settings object.settings includes a templateId, any previous global template set by QRCodeJs.setTemplate() will be replaced. Similarly, if settings.data is provided, it calls QRCodeJs.setData(settings.data), and if settings.options is provided, it calls QRCodeJs.setOptions(settings.options).null will clear all static configurations (template, style, text, border, image, data, and options).Example:
const myGlobalPreset: SettingsOptions = {
name: 'CompanyStandard',
data: 'https://company.com/default-link', // Will call QRCodeJs.setData()
image: 'https://company.com/assets/logo.png', // Will call QRCodeJs.setImage()
templateId: 'company-wide-template', // Assumes this template ID exists, will call QRCodeJs.setTemplateId()
options: { // Will call QRCodeJs.setOptions()
qrOptions: { errorCorrectionLevel: 'H' },
margin: 5
}
};
QRCodeJs.setSettings(myGlobalPreset);
// Subsequent QRCodeJs instances will use these global defaults
const qr1 = new QRCodeJs({ /* data will be 'https://company.com/default-link' */ });
const qr2 = new QRCodeJs({ data: 'https://company.com/specific-page' }); // Overrides data from preset
// To clear all global settings:
// QRCodeJs.setSettings(null);
useSettings()The QRCodeBuilder.useSettings(settings: SettingsOptions) method applies a SettingsOptions object as a new baseline for a specific builder chain.
useSettings() on a builder instance will reset any configurations previously applied to that builder instance via methods like useTemplate(), useStyle(), useBorder(), useText(), useImage(), useData(), or useOptions(). The provided settings object then establishes the new comprehensive baseline for that builder.useSettings() (e.g., .useStyle(), .options()) will then modify this new baseline.Example:
const eventSpecificSettings: SettingsOptions = {
name: 'ConferenceQR',
data: 'https://conference-event.com/details', // Baseline data for this builder
image: 'event-logo.png', // Baseline image
style: { dotsOptions: { type: 'classy', color: '#005FAB' } }, // Baseline style
borderId: 'event-frame' // Baseline border
};
const qrEvent = QRCodeJs.useTemplate('basic') // Initial template (will be reset by useSettings)
.useStyle({ dotsOptions: { color: 'red'} }) // This style will also be reset
.useSettings(eventSpecificSettings) // Resets builder and applies eventSpecificSettings as baseline
.useOptions({ margin: 20 }) // Further customizes the baseline from eventSpecificSettings
.options({ data: 'https://conference-event.com/live-updates' }) // Final data override
.build();
qrEvent.append(document.getElementById('event-qr-container'));
QRCode.js offers flexible ways to manage configurations, from setting global defaults that apply to all new instances to using a fluent builder pattern for specific instances.
Static methods on the QRCodeJs class allow you to define default configurations that will be automatically applied to all QRCodeJs instances created after these defaults are set. This is useful for establishing a baseline style or configuration for your application.
QRCodeJs.setTemplate(templateNameOrOptions | null) / QRCodeJs.setTemplateId(id | null): Sets a global default template.QRCodeJs.setStyle(styleNameOrOptions | null) / QRCodeJs.setStyleId(id | null): Sets a global default style.QRCodeJs.setBorder(borderNameOrOptions | null) / QRCodeJs.setBorderId(id | null): Sets a global default border configuration.QRCodeJs.setText(textNameOrOptions | null, overrideOpts?: MethodOverrideOptions) / QRCodeJs.setTextId(id | null, overrideOpts?: MethodOverrideOptions): Sets global default border text. The overrideOpts (e.g., { override: true }) ensures this text takes precedence over text set by other means (e.g., in instance options).QRCodeJs.setImage(imageUrl | null, overrideOpts?: MethodOverrideOptions): Sets a global default image. overrideOpts ensures this image takes precedence over images set by other means.QRCodeJs.setData(data | null, overrideOpts?: MethodOverrideOptions): Sets a global default data string. overrideOpts ensures this data takes precedence.QRCodeJs.setOptions(options | null, overrideOpts?: MethodOverrideOptions): Sets global default options that are merged deeply. overrideOpts ensures higher precedence for these options over those set by other means for the properties they cover.QRCodeJs.setSettings(settings | null): A powerful static method to set multiple global defaults at once using a comprehensive SettingsOptions object (see Centralized Configuration with Settings). This method acts as a macro, calling the other static setters (like setTemplate, setStyle, setData, setImage, setOptions, etc.) based on the provided settings object. It will override/reset any previously set static configurations for the aspects it covers.Any options provided during the instantiation of new QRCodeJs({...}) or through builder methods will override these global defaults for that specific instance, unless an override: true was used with a static setter for that specific property. Call any of these setters with null to clear the respective global default.
Example: Setting various global defaults
// Set a global template and data with override
QRCodeJs.setTemplate('dots');
QRCodeJs.setData('https://example-global.com', { override: true }); // This data will be hard to override
const qr1 = new QRCodeJs({ /* data will be https://example-global.com */ });
const qrWithDifferentData = new QRCodeJs({ data: 'https://another-link.com' }); // data will still be https://example-global.com due to override
// Using setSettings to define multiple global defaults
const globalBrandSettings: SettingsOptions = {
templateId: 'brand-template', // Assumes this ID exists
style: { dotsOptions: { color: '#AA0000' } }, // Dark red dots
image: 'https://brand.com/logo.svg', // Global brand logo
data: 'https://brand-default.com', // Default data for this setting
options: { margin: 10, qrOptions: { errorCorrectionLevel: 'M' } }
};
QRCodeJs.setSettings(globalBrandSettings);
// This will override the previous QRCodeJs.setTemplate('dots').
// However, the data 'https://example-global.com' (set with override:true) will persist.
// All other aspects from globalBrandSettings (style, image, options) will apply.
const qrBrand = new QRCodeJs({ /* data is 'https://example-global.com', other options from globalBrandSettings apply */ });
// Reset all global settings
QRCodeJs.setSettings(null); // This clears all static defaults, including the overridden data.
const qrAfterClear = new QRCodeJs({ data: 'https://new-data.com' }); // Now uses 'https://new-data.com'
The static use methods (e.g., QRCodeJs.useTemplate(), QRCodeJs.useStyle(), QRCodeJs.useSettings()) initiate a builder pattern. They return a QRCodeBuilder instance pre-configured with the specified settings. This approach does not set global defaults.
QRCodeJs.useTemplate(templateNameOrOptions) / QRCodeJs.useTemplateId(id): Initiates a builder with a template.QRCodeJs.useStyle(styleNameOrOptions) / QRCodeJs.useStyleId(id): Initiates a builder with a style.QRCodeJs.useBorder(borderNameOrOptions) / QRCodeJs.useBorderId(id): Initiates a builder with border settings.QRCodeJs.useText(textNameOrOptions, overrideOpts?: MethodOverrideOptions) / QRCodeJs.useTextId(id, overrideOpts?: MethodOverrideOptions): Initiates a builder with border text settings. overrideOpts ensures precedence over text in final .options().QRCodeJs.useImage(imageUrl, overrideOpts?: MethodOverrideOptions): Initiates a builder with an image. overrideOpts ensures precedence over image in final .options().QRCodeJs.useData(data, overrideOpts?: MethodOverrideOptions): Applies a data string to the current builder configuration. overrideOpts ensures precedence over data in final .options().QRCodeJs.useOptions(options, overrideOpts?: MethodOverrideOptions): Applies a partial options object to the current builder configuration. overrideOpts ensures higher precedence for these options over those in final .options() for the properties they cover.QRCodeJs.useSettings(settings): Applies a comprehensive SettingsOptions object as a new baseline for the builder chain, resetting any configurations previously applied to that builder instance via other use methods (see Centralized Configuration with Settings).You must chain these calls with .options(finalOptions) (which also builds the instance) or .build() to get the final QRCodeJs instance. The .options() method takes the final configuration, including the required data property (unless provided by useData, useSettings, or a global default with override) and any ultimate overrides.
Example: Builder Pattern Usage
// Start with a template, then layer styles and data
const qrBuilder1 = QRCodeJs.useTemplate('rounded')
.useStyle({ dotsOptions: { color: '#007BFF' } }) // Blue override for dots
.useData('Built with template and style')
.options({ margin: 10 }); // Final options and build
// Using useSettings to establish a baseline for the builder
const eventSettings: SettingsOptions = {
data: 'https://myevent.com',
image: 'event-logo.png',
styleId: 'event-style' // Assumes 'event-style' is a defined style
};
const qrEvent = QRCodeJs.useSettings(eventSettings) // Establishes baseline from eventSettings
.useText({ topValue: 'SCAN FOR EVENT DETAILS' }) // Adds text to the baseline
.useOptions({ qrOptions: { errorCorrectionLevel: 'H' } }, { override: true }) // These options take high precedence over final .options()
.options({ data: 'Final Event Data Override', qrOptions: { errorCorrectionLevel: 'M' } });
// Final data overrides eventSettings.data.
// errorCorrectionLevel 'M' from .options() is overridden by 'H' from .useOptions() with override:true.
Understanding the order in which options are applied is key:
baseQRTemplateOptions).QRCodeJs.setTemplate(), QRCodeJs.setStyle(), QRCodeJs.setData(), QRCodeJs.setOptions(), QRCodeJs.setSettings(), etc.
QRCodeJs.setSettings() calls individual static setters, so its components follow this rule.{ override: true } (e.g., setData('data', { override: true })) will have their specific property take precedence over less specific global defaults or later non-overriding instance options.QRCodeBuilder.useSettings(settings) is called, it resets previous builder steps for that instance and establishes settings as the new baseline.useTemplate, useStyle, useData, useOptions, etc.) are applied sequentially. If multiple methods affect the same property, later calls generally override earlier ones within the builder chain (either before useSettings or after it on the new baseline).{ override: true } (e.g., useData('data', { override: true })) will have their specific property take precedence within the builder’s accumulated state before the final .options() call, overriding values from the final .options() for those specific properties..options() call on Builder / Constructor Options: Options passed directly here (e.g., new QRCodeJs(options) or builder.options(options)) override global defaults and accumulated builder configurations, unless a global or builder setting for a specific property was set with { override: true }.In summary for a single property (e.g., data or image):
{ override: true } (either static or builder) is very sticky and will generally win..options()) override builder-accumulated options (that were not set with override).const qrCode = new QRCodeJs({
data: 'https://example.com',
dotsOptions: {
type: 'rounded',
color: '#0033CC',
size: 12
}
});
qrCode.append(document.getElementById('qr-container'));
const qrCode = new QRCodeJs({
data: 'https://example.com',
shape: 'square',
qrOptions: {
errorCorrectionLevel: 'H'
},
dotsOptions: {
type: 'classy',
color: '#000000'
},
cornersSquareOptions: {
type: 'outpoint',
color: '#FF0000'
},
cornersDotOptions: {
type: 'dot',
color: '#FF0000'
},
backgroundOptions: {
color: '#FFECDB',
round: 0.2
}
});
const qrCode = new QRCodeJs({
data: 'https://example.com',
image: 'https://example.com/logo.png',
imageOptions: {
mode: 'center',
imageSize: 0.3,
margin: 1,
crossOrigin: 'anonymous',
fill: {
color: 'rgba(255,255,255,1)'
}
},
dotsOptions: {
type: 'dot',
color: '#4267B2'
}
});
const qrCode = new QRCodeJs({
data: 'https://example.com',
dotsOptions: {
type: 'rounded',
color: '#0033CC'
},
borderOptions: {
hasBorder: true,
thickness: 50,
color: '#002683',
radius: '5%'
}
});
const qrCode = new QRCodeJs({
data: 'https://example.com',
dotsOptions: {
type: 'extraRounded',
gradient: {
type: 'radial',
colorStops: [
{ offset: 0, color: '#8F00FF' },
{ offset: 1, color: '#0080FF' }
]
}
},
backgroundOptions: {
color: '#FFFFFF',
round: 0.1
},
borderOptions: {
hasBorder: true,
thickness: 50,
color: '#002683',
radius: '40%',
decorations: {
top: {
enableText: true,
type: 'text',
value: 'SCAN ME',
style: {
fontFace: 'Helvetica',
fontSize: 28,
fontColor: '#ffffff',
letterSpacing: 2,
fontWeight: 'bold'
}
},
bottom: {
enableText: true,
type: 'text',
style: {
fontFace: 'Arial',
fontSize: 20,
fontColor: '#ffffff'
}
}
},
borderOuter: {
color: '#001255',
thickness: 10
},
borderInner: {
color: '#334499',
thickness: 5
}
}
});
const qrCode = new QRCodeJs({
data: 'Gradient Example',
dotsOptions: {
type: 'rounded',
gradient: {
type: 'linear',
rotation: Math.PI / 4,
colorStops: [
{ offset: 0, color: '#ff5733' },
{ offset: 1, color: '#c70039' }
]
}
},
backgroundOptions: {
gradient: {
type: 'radial',
colorStops: [
{ offset: 0, color: '#ffffff' },
{ offset: 1, color: '#e0e0e0' }
]
}
},
cornersSquareOptions: {
type: 'dot',
gradient: {
type: 'linear',
rotation: 0,
colorStops: [
{ offset: 0, color: '#c70039' },
{ offset: 1, color: '#900c3f' }
]
}
}
});
const qrCode = new QRCodeJs({
data: 'Layout within Border',
scale: 0.75, // Scale the QR code down to 75% within the border
offset: -15, // Move the QR code up slightly within the border
dotsOptions: {
type: 'square',
color: '#333333'
},
borderOptions: {
hasBorder: true,
thickness: 60,
color: '#CCCCCC',
radius: '10%',
decorations: {
bottom: {
enableText: true,
type: 'text',
value: 'SCALED & OFFSET',
style: {
fontFace: 'Arial',
fontSize: 24,
fontColor: '#555555',
fontWeight: 'normal'
}
}
}
}
});
const qrCode = new QRCodeJs({
data: 'https://example.com',
shape: 'circle',
dotsOptions: {
type: 'rounded',
color: '#6200EA'
},
cornersDotOptions: {
type: 'dot',
color: '#00C853'
},
cornersSquareOptions: {
type: 'rounded',
color: '#00C853'
},
backgroundOptions: {
color: '#FFFFFF'
}
});
new QRCodeJs(options: QRCodeJsOptions)
append()Appends the QR code to a container element.
qrCode.append(
container: HTMLElement,
options?: { clearContainer?: boolean }
): QRCodeJs | undefined
serialize()Converts the QR code to an SVG string.
qrCode.serialize(inverted?: boolean): Promise<string | undefined>
download()Downloads the QR code as a file.
qrCode.download(
downloadOptions?: {
name?: string;
extension: 'svg' | 'png' | 'jpeg' | 'webp'
},
canvasOptions?: CanvasOptions
): Promise<void>
update()Updates the QR code with new options.
qrCode.update(options?: RecursivePartial<Options>): void
validateScanning()Validates that the QR code is scannable.
qrCode.validateScanning(
validatorId?: string,
debug?: boolean
): Promise<ScanValidatorResponse>
These helper methods allow attaching or retrieving metadata on a QR code instance.
qrCode.setId(id?: string): this
qrCode.setName(name?: string): this
qrCode.setDescription(description?: string): this
qrCode.setMetadata(metadata?: Record<string, any>): this
qrCode.getId(): string | undefined
qrCode.getName(): string | undefined
qrCode.getDescription(): string | undefined
qrCode.getMetadata(): Record<string, any> | undefined
qrCode.getSettings(): SettingsOptions & { options: Options }
These methods are called directly on the QRCodeJs class (e.g., QRCodeJs.setTemplate()).
The following static methods are available on the QRCodeJs class.
setTemplate(templateNameOrOptions | null) / setTemplateId(id | null): Sets a global default template.setStyle(styleNameOrOptions | null) / setStyleId(id | null): Sets a global default style.setBorder(borderNameOrOptions | null) / setBorderId(id | null): Sets a global default border configuration.setText(textNameOrOptions | null, overrideOpts?) / setTextId(id | null, overrideOpts?): Sets global default border text. overrideOpts (e.g., { override: true }) ensures precedence.setImage(imageUrl | null, overrideOpts?): Sets a global default image. overrideOpts ensures precedence.setData(data | null, overrideOpts?): Sets a global default data string. overrideOpts ensures precedence.setOptions(options | null, overrideOpts?): Sets global default options (merged deeply). overrideOpts ensures higher precedence.setSettings(settings | null): Sets multiple global defaults from a SettingsOptions object. Acts as a macro, calling other static setters. Clears all static defaults if null is passed.All set... methods return typeof QRCodeJs for chaining.
These methods initiate a QRCodeBuilder instance.
useTemplate(templateNameOrOptions) / useTemplateId(id): Starts builder with a template.useStyle(styleNameOrOptions) / useStyleId(id): Starts builder with a style.useBorder(borderNameOrOptions) / useBorderId(id): Starts builder with border settings.useText(textNameOrOptions, overrideOpts?) / useTextId(id, overrideOpts?): Starts builder with border text. overrideOpts ensures precedence over text in final .options().useImage(imageUrl, overrideOpts?): Starts builder with an image. overrideOpts ensures precedence over image in final .options().useData(data, overrideOpts?): Applies data to the builder. overrideOpts ensures precedence over data in final .options().useOptions(options, overrideOpts?): Applies options to the builder. overrideOpts ensures precedence over options in final .options().useSettings(settings): Applies a SettingsOptions object as a new baseline for the builder, resetting prior builder configurations.All use... methods return a QRCodeBuilder instance for chaining.
Example Signatures (Illustrative):
// Global Defaults
static setData(data: string | null, overrideOpts?: { override?: boolean }): typeof QRCodeJs;
static setOptions(options: RecursivePartial<Options> | null, overrideOpts?: { override?: boolean }): typeof QRCodeJs;
static setSettings(settings: SettingsOptions | null): typeof QRCodeJs;
// Builder Initiators & Methods
static useData(data: string, overrideOpts?: { override?: boolean }): QRCodeBuilder;
static useOptions(options: RecursivePartial<Options>, overrideOpts?: { override?: boolean }): QRCodeBuilder;
static useSettings(settings: SettingsOptions): QRCodeBuilder;
// (Other set... and use... methods follow similar patterns)
useTemplate, useStyle, useSettings, build, etc.)QRCode.js offers a fluent builder pattern for a more readable and chainable way to configure and create QR codes, especially when combining templates, styles, and custom options.
Instead of passing all options to the constructor, you can start with a base template, style, border, or image using QRCodeJs.useTemplate(), QRCodeJs.useStyle(), QRCodeJs.useBorder(), or QRCodeJs.useImage(). These methods return a QRCodeBuilder instance. You can then chain further .useTemplate(), .useStyle(), .useBorder(), .useImage(), and finally .options() or .build() to finalize the configuration.
QRCodeJs.useTemplate(template): Starts a builder with a predefined or custom template.QRCodeJs.useStyle(style): Starts a builder and applies a predefined or custom style.QRCodeJs.useBorder(border): Starts a builder and applies a predefined or custom border configuration.QRCodeJs.useImage(imageUrl): Starts a builder and sets an image..useTemplate(template) (on builder): Applies another template. Options merge..useStyle(style) (on builder): Applies another style. Options merge..useBorder(border) (on builder): Applies a border configuration. Options merge..useImage(imageUrl) (on builder): Sets or overrides the image..options(options) (on builder): Merges final specific options and returns the QRCodeJs instance..build() (on builder, optional method if options(options) is NOT called): Creates the QRCodeJs instance with the accumulated configuration.You can chain useTemplate, useStyle, useBorder, and useImage calls. The options are merged progressively. If multiple methods define the same option (e.g., dotsOptions.color from a template and a style, or image from useImage and a template), the option from the last applied method in the chain for that specific property will generally take precedence. The final .options() call provides the ultimate override.
1. Start with a Template, Add Options:
const qrFromTemplate = QRCodeJs.useTemplate('rounded') // Start with 'rounded' template
.options({ // Merge specific options
data: 'Data for rounded QR',
margin: 10
})
.build(); // Build the final instance
qrFromTemplate.append(document.getElementById('qr-container-1'));
2. Start with a Style, Add Options:
const myStyle = {
dotsOptions: { type: 'dots', color: '#FF6347' }, // Tomato dots
backgroundOptions: { color: '#F0F8FF' } // AliceBlue background
};
const qrFromStyle = QRCodeJs.useStyle(myStyle) // Start with custom style
.options({ // Merge specific options
data: 'Data for styled QR',
qrOptions: { errorCorrectionLevel: 'H' }
})
.build();
qrFromStyle.append(document.getElementById('qr-container-2'));
3. Chain Template and Style:
const qrCombined = QRCodeJs.useTemplate('dots') // Start with 'dots' template (black dots)
.useStyle({ dotsOptions: { color: '#4682B4' } }) // Apply style, overriding dot color to SteelBlue
.useImage('https://example.com/logo.png') // Add an image
.options({ data: 'Template + Style + Image' })
.build();
qrCombined.append(document.getElementById('qr-container-3'));
4. Build without final options:
// Assume 'data' is part of the template or style
const qrBuildDirectly = QRCodeJs.useTemplate({
data: 'Data in template',
dotsOptions: { type: 'square' }
})
.build(); // Build directly if all options are set
qrBuildDirectly.append(document.getElementById('qr-container-4'));
interface Options {
// Core Data & QR Algorithm
data: string; // Required: Content to encode
qrOptions: {
typeNumber: number; // Default 0 (auto)
mode?: Mode; // Default: auto-detected
errorCorrectionLevel: ErrorCorrectionLevel; // Default 'Q'
};
// Overall Shape & Layout
shape: ShapeType; // Default 'square'
margin?: number; // Default 0: Space around QR code (pixels)
isResponsive?: boolean; // Default false: Allow SVG resizing
scale?: number; // Default 1: Scale QR code within container/border (0-1.5)
offset?: number; // Default 0: Vertical offset relative to center
verticalOffset?: number; // Default 0: Absolute vertical offset
horizontalOffset?: number; // Default 0: Absolute horizontal offset
// Dot Styling
dotsOptions: {
type: DotType; // Default 'square'
color: string; // Default '#000000'
gradient?: Gradient;
size: number; // Default 10 (pixels)
};
// Corner Square Styling (Overrides dotsOptions)
cornersSquareOptions?: {
type?: CornerSquareType; // Default: inherits dotsOptions.type or 'dot'
color?: string; // Default: inherits dotsOptions.color or '#000000'
gradient?: Gradient;
};
// Corner Dot Styling (Overrides cornersSquareOptions)
cornersDotOptions?: {
type?: CornerDotType; // Default: inherits cornersSquareOptions.type or 'dot'
color?: string; // Default: inherits cornersSquareOptions.color or '#000000'
gradient?: Gradient;
};
// Background Styling
backgroundOptions?: {
color?: string; // Default '#FFFFFF'
gradient?: Gradient;
round?: number | string; // Default 0: Corner rounding (0-1 or %)
} | false; // Set to false to disable background
// Image Embedding
image?: string | Buffer | Blob; // Image source (URL, Buffer, Blob)
imageOptions: {
mode?: ImageMode; // Default 'center'
imageSize: number; // Default 0.4: Relative image size (0-1)
margin: number; // Default 0: Margin around image (dot units)
crossOrigin?: string; // Default undefined: CORS setting
fill?: {
color: string; // Default 'rgba(255,255,255,1)'
gradient?: Gradient;
};
};
borderOptions?: {
hasBorder: boolean; // Master switch to enable/disable borders
thickness: number; // Thickness of the main border in pixels
color: string; // Color of the main border
radius: string; // Corner rounding of the border (e.g., '10%', '20px')
noBorderThickness: number; // Thickness for border sides with disabled decorations
background?: string; // Background color for the border area
inner?: {
radius: string;
scale: number;
horizontalOffset: number;
verticalOffset: number;
};
borderOuter?: {
color: string;
thickness: number;
};
borderInner?: {
color: string;
thickness: number;
};
decorations?: {
top?: DecorationOptions;
right?: DecorationOptions;
bottom?: DecorationOptions;
left?: DecorationOptions;
};
};
}
// Supporting Interfaces
interface Gradient {
type: 'linear' | 'radial';
rotation?: number;
colorStops: Array<{ offset: number; color: string }>;
}
interface DecorationOptions {
disabled: boolean;
enableText: boolean;
offset: number;
curveAdjustment: number;
curveDisabled: boolean;
curveRadius: string;
type: 'text' | 'image';
value: string;
style?: {
fontFace: string;
fontSize: number;
fontColor: string;
letterSpacing: number;
fontWeight: 'normal' | 'bold';
};
}
// Enums
enum ShapeType {
square = 'square',
circle = 'circle'
}
enum Mode {
numeric = 'numeric',
alphanumeric = 'alphanumeric',
byte = 'byte',
kanji = 'kanji',
unicode = 'unicode'
}
enum ErrorCorrectionLevel {
L = 'L', // 7% error recovery
M = 'M', // 15% error recovery
Q = 'Q', // 25% error recovery
H = 'H' // 30% error recovery
}
enum DotType {
dot = 'dot',
square = 'square',
rounded = 'rounded',
extraRounded = 'extra-rounded',
classy = 'classy',
classyRounded = 'classy-rounded',
verticalLine = 'vertical-line',
horizontalLine = 'horizontal-line',
randomDot = 'random-dot',
smallSquare = 'small-square',
tinySquare = 'tiny-square',
star = 'star',
plus = 'plus',
diamond = 'diamond'
}
enum CornerSquareType {
dot = 'dot',
square = 'square',
rounded = 'rounded',
classy = 'classy',
outpoint = 'outpoint',
inpoint = 'inpoint'
}
enum CornerDotType {
dot = 'dot',
square = 'square',
heart = 'heart',
rounded = 'rounded',
classy = 'classy',
outpoint = 'outpoint',
inpoint = 'inpoint'
}
enum ImageMode {
center = 'center',
overlay = 'overlay',
background = 'background'
}
QRCode.js provides comprehensive metadata management capabilities for organizing, tracking, and categorizing QR code instances. This section covers the various metadata features available through both instance methods and the builder pattern.
Metadata in QRCode.js allows you to:
Once a QR code instance is created, you can manage its metadata using chainable methods:
const qrCode = new QRCodeJs({
data: 'https://company.com/products/laptop-pro'
});
// Chain metadata methods for clean configuration
qrCode
.setId('product-laptop-pro-2024')
.setName('Laptop Pro QR Code')
.setDescription('QR code for Laptop Pro product page with specifications and pricing')
.setMetadata({
productId: 'laptop-pro-001',
category: 'electronics',
subcategory: 'laptops',
brand: 'TechCorp',
price: 1299.99,
inStock: true,
campaign: 'back-to-school-2024',
trackingEnabled: true,
analytics: {
expectedScans: 1000,
conversionTarget: 50
}
});
// Access individual metadata components
const qrId = qrCode.getId(); // 'product-laptop-pro-2024'
const qrName = qrCode.getName(); // 'Laptop Pro QR Code'
const qrDescription = qrCode.getDescription(); // 'QR code for Laptop Pro...'
const customMetadata = qrCode.getMetadata(); // { productId: 'laptop-pro-001', ... }
// Get comprehensive settings and configuration
const settings = qrCode.getSettings();
console.log('Complete QR Configuration:', settings);
The builder pattern provides elegant metadata assignment during QR code construction:
const enterpriseQR = QRCodeJs.useTemplate('corporate')
.useId('campaign-summer-2024-001')
.useName('Summer Campaign Landing Page')
.useDescription('Primary QR code for summer marketing campaign directing to landing page')
.useMetadata({
campaignId: 'summer-2024',
campaignType: 'seasonal',
targetAudience: ['millennials', 'gen-z'],
channels: ['social-media', 'print', 'email'],
budget: 25000,
duration: {
start: '2024-06-01',
end: '2024-08-31'
},
kpis: {
primary: 'conversion-rate',
secondary: ['engagement', 'reach']
},
geography: {
regions: ['north-america', 'europe'],
languages: ['en', 'es', 'fr', 'de']
}
})
.options({
data: 'https://company.com/summer-campaign-2024',
image: 'https://company.com/assets/summer-logo.png'
});
class CMSQRManager {
static createContentQR(content) {
const metadata = {
contentId: content.id,
contentType: content.type,
title: content.title,
author: content.author,
publishDate: content.publishDate,
lastModified: content.lastModified,
tags: content.tags,
language: content.language,
seoScore: content.seoScore,
readingTime: content.estimatedReadingTime
};
return QRCodeJs.useTemplate('cms-standard')
.useId(`cms-${content.type}-${content.id}`)
.useName(`${content.title} - ${content.type}`)
.useDescription(`QR code for ${content.type}: ${content.title}`)
.useMetadata(metadata)
.options({
data: `https://cms.company.com/content/${content.id}`,
qrOptions: { errorCorrectionLevel: 'M' }
});
}
}
// Usage
const articleQR = CMSQRManager.createContentQR({
id: 'art-2024-0315',
type: 'article',
title: 'Future of Sustainable Technology',
author: 'Dr. Jane Smith',
publishDate: '2024-03-15',
lastModified: '2024-03-20',
tags: ['technology', 'sustainability', 'innovation'],
language: 'en',
seoScore: 94,
estimatedReadingTime: '8 minutes'
});
class CampaignQRGenerator {
constructor(campaignConfig) {
this.config = campaignConfig;
}
createChannelQR(channel, specific = {}) {
const baseMetadata = {
campaignId: this.config.id,
campaignName: this.config.name,
channel: channel.name,
channelType: channel.type,
medium: channel.medium,
budget: channel.budget,
expectedReach: channel.expectedReach,
createdAt: new Date().toISOString(),
...this.config.globalMetadata
};
return QRCodeJs.useTemplate(this.config.template)
.useId(`${this.config.id}-${channel.name}-${Date.now()}`)
.useName(`${this.config.name} - ${channel.displayName}`)
.useDescription(`${this.config.name} campaign QR for ${channel.displayName}`)
.useMetadata({ ...baseMetadata, ...specific })
.options({
data: `${this.config.baseUrl}?utm_source=${channel.name}&utm_medium=${channel.medium}&utm_campaign=${this.config.id}`,
...channel.qrOptions
});
}
}
// Usage
const campaignGen = new CampaignQRGenerator({
id: 'holiday-2024',
name: 'Holiday Sale Campaign',
template: 'festive',
baseUrl: 'https://store.company.com/holiday-sale',
globalMetadata: {
brand: 'TechCorp',
season: 'holiday',
year: 2024,
department: 'marketing'
}
});
const socialQR = campaignGen.createChannelQR(
{
name: 'instagram',
displayName: 'Instagram',
type: 'social',
medium: 'social-media',
budget: 5000,
expectedReach: 50000,
qrOptions: { margin: 20 }
},
{
platform: 'instagram',
contentType: 'story',
demographics: 'young-adults'
}
);
class AnalyticsQRWrapper {
static enhanceWithAnalytics(qrInstance, analyticsConfig) {
const enhancedMetadata = {
...qrInstance.getMetadata(),
analytics: {
trackingId: analyticsConfig.trackingId,
platform: analyticsConfig.platform,
goals: analyticsConfig.goals,
customDimensions: analyticsConfig.customDimensions,
autoTrack: analyticsConfig.autoTrack,
enableHeatmap: analyticsConfig.enableHeatmap,
retentionPeriod: analyticsConfig.retentionPeriod
},
privacy: {
gdprCompliant: true,
anonymized: analyticsConfig.anonymized,
consentRequired: analyticsConfig.consentRequired
}
};
qrInstance.setMetadata(enhancedMetadata);
return qrInstance;
}
static createAnalyticsReport(qrInstance) {
const metadata = qrInstance.getMetadata();
const settings = qrInstance.getSettings();
return {
qrInfo: {
id: qrInstance.getId(),
name: qrInstance.getName(),
description: qrInstance.getDescription()
},
configuration: settings,
metadata: metadata,
analyticsReadiness: this.validateAnalyticsSetup(metadata),
reportGeneratedAt: new Date().toISOString()
};
}
static validateAnalyticsSetup(metadata) {
const analytics = metadata?.analytics;
return {
hasTrackingId: !!analytics?.trackingId,
hasGoals: !!(analytics?.goals && analytics.goals.length > 0),
gdprCompliant: metadata?.privacy?.gdprCompliant === true,
autoTrackEnabled: analytics?.autoTrack === true
};
}
}
// Usage
const productQR = QRCodeJs.useTemplate('product')
.useId('product-smartphone-x1')
.useName('Smartphone X1 Product Page')
.useMetadata({
productId: 'smartphone-x1',
category: 'mobile',
price: 699.99
})
.options({
data: 'https://store.company.com/smartphone-x1'
});
const enhancedQR = AnalyticsQRWrapper.enhanceWithAnalytics(productQR, {
trackingId: 'GA-123456789',
platform: 'google-analytics',
goals: ['purchase', 'add-to-cart', 'view-specifications'],
customDimensions: {
productCategory: 'mobile',
priceRange: '600-800',
season: 'q1-2024'
},
autoTrack: true,
enableHeatmap: true,
retentionPeriod: '2-years',
anonymized: true,
consentRequired: false
});
const analyticsReport = AnalyticsQRWrapper.createAnalyticsReport(enhancedQR);
console.log('QR Analytics Report:', analyticsReport);
// Define a standardized metadata schema
const MetadataSchema = {
// Core identification
id: 'string (required)',
name: 'string (required)',
description: 'string (required)',
// Lifecycle tracking
createdAt: 'ISO 8601 timestamp',
updatedAt: 'ISO 8601 timestamp',
createdBy: 'string (user identifier)',
lastModifiedBy: 'string (user identifier)',
version: 'string (semantic versioning)',
// Business context
businessUnit: 'string',
department: 'string',
project: 'string',
campaign: 'string',
// Technical details
environment: 'development | staging | production',
region: 'string',
locale: 'string (ISO 639-1)',
// Analytics and tracking
analytics: {
enabled: 'boolean',
platform: 'string',
goals: 'string[]',
customDimensions: 'Record<string, any>'
},
// Compliance and governance
dataRetention: 'string (duration)',
privacyLevel: 'public | internal | confidential | restricted',
complianceFlags: 'string[]'
};
class MetadataValidator {
static validateRequiredFields(metadata) {
const required = ['id', 'name', 'description'];
const missing = required.filter(field => !metadata[field]);
if (missing.length > 0) {
throw new Error(`Missing required metadata fields: ${missing.join(', ')}`);
}
}
static sanitizeMetadata(metadata) {
return {
...metadata,
// Ensure timestamps are ISO strings
createdAt: metadata.createdAt || new Date().toISOString(),
updatedAt: new Date().toISOString(),
// Sanitize strings
name: metadata.name?.trim(),
description: metadata.description?.trim(),
// Ensure arrays are arrays
tags: Array.isArray(metadata.tags) ? metadata.tags : [],
// Validate email format for creator fields
createdBy: this.validateEmail(metadata.createdBy)
};
}
static validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return email && emailRegex.test(email) ? email : null;
}
}
// Usage with validation
function createValidatedQR(data, metadata) {
try {
MetadataValidator.validateRequiredFields(metadata);
const sanitizedMetadata = MetadataValidator.sanitizeMetadata(metadata);
return QRCodeJs.useTemplate('validated')
.useId(sanitizedMetadata.id)
.useName(sanitizedMetadata.name)
.useDescription(sanitizedMetadata.description)
.useMetadata(sanitizedMetadata)
.options({ data });
} catch (error) {
console.error('QR creation failed:', error.message);
throw error;
}
}
class MetadataVersionManager {
static CURRENT_VERSION = '2.1.0';
static migrateMetadata(metadata) {
const version = metadata.schemaVersion || '1.0.0';
let migrated = { ...metadata };
if (this.isVersionLess(version, '2.0.0')) {
migrated = this.migrateTo2_0_0(migrated);
}
if (this.isVersionLess(version, '2.1.0')) {
migrated = this.migrateTo2_1_0(migrated);
}
migrated.schemaVersion = this.CURRENT_VERSION;
migrated.lastMigration = new Date().toISOString();
return migrated;
}
static migrateTo2_0_0(metadata) {
return {
...metadata,
// Migrate old tracking field to new analytics structure
analytics: {
enabled: metadata.tracking?.enabled || false,
platform: metadata.tracking?.platform || 'unknown',
goals: metadata.tracking?.events || []
},
// Remove deprecated fields
tracking: undefined
};
}
static migrateTo2_1_0(metadata) {
return {
...metadata,
// Add new compliance fields with defaults
compliance: {
dataRetention: metadata.compliance?.dataRetention || '1-year',
privacyLevel: metadata.compliance?.privacyLevel || 'internal'
}
};
}
static isVersionLess(version1, version2) {
const v1Parts = version1.split('.').map(Number);
const v2Parts = version2.split('.').map(Number);
for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
const v1Part = v1Parts[i] || 0;
const v2Part = v2Parts[i] || 0;
if (v1Part < v2Part) return true;
if (v1Part > v2Part) return false;
}
return false;
}
}
class QRDatabaseManager {
static async saveQRMetadata(qrInstance) {
const metadata = {
id: qrInstance.getId(),
name: qrInstance.getName(),
description: qrInstance.getDescription(),
customMetadata: qrInstance.getMetadata(),
settings: qrInstance.getSettings(),
createdAt: new Date(),
updatedAt: new Date()
};
// Save to database (pseudo-code)
return await database.qrCodes.create(metadata);
}
static async loadQRMetadata(qrId) {
const record = await database.qrCodes.findById(qrId);
if (!record) return null;
// Recreate QR instance with stored metadata
const qrInstance = new QRCodeJs(record.settings.options || { data: record.data });
qrInstance
.setId(record.id)
.setName(record.name)
.setDescription(record.description)
.setMetadata(record.customMetadata);
return qrInstance;
}
}
This comprehensive metadata management system enables enterprise-level QR code organization, tracking, and governance while maintaining flexibility for various use cases and integration requirements.
QRCode.js by QR-Platform is free for personal projects, open-source projects, or general non-commercial use. For commercial use, a license is required.
See the full license at LICENSE.md for more information. For commercial licenses, including full source code and support, contact qr.platform.com@gmail.com.