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'));
data
string
'https://example.com'
shape
ShapeType
enum'square'
'square'
, 'circle'
shape: 'circle'
margin
number
0
margin: 20
isResponsive
false
, fixed width
and height
attributes are set on the SVG.boolean
false
isResponsive: true
qrOptions
Options that affect the QR code generation algorithm.
typeNumber
TypeNumber
(0-40)0
(auto-determine based on content)qrOptions: {
typeNumber: 4
}
mode
Mode
enum'numeric'
, 'alphanumeric'
, 'byte'
, 'kanji'
, 'unicode'
qrOptions: {
mode: 'alphanumeric'
}
errorCorrectionLevel
ErrorCorrectionLevel
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.
scale
number
(0 to 1.5)1
scale: 0.8 // Make QR code 80% of available space
offset
number
0
offset: -10 // Move QR code 10px up
verticalOffset
number
0
verticalOffset: 5 // Move QR code 5px down
horizontalOffset
number
0
horizontalOffset: -5 // Move QR code 5px left
dotsOptions
)Controls the appearance of individual QR code dots.
type
DotType
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'
}
color
string
(CSS color, hex, rgb, rgba)'#000000'
dotsOptions: {
color: '#FF5733'
}
size
number
10
dotsOptions: {
size: 12
}
gradient
Gradient
object (see Gradients)undefined
dotsOptions: {
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.
type
CornerSquareType
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'
}
color
string
(CSS color, hex, rgb, rgba)dotsOptions.color
or uses '#000000'
cornersSquareOptions: {
color: '#0000FF'
}
gradient
dotsOptions.gradient
)Gradient
object (see Gradients)undefined
cornersSquareOptions: {
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.
type
CornerDotType
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'
}
color
string
(CSS color, hex, rgb, rgba)cornersSquareOptions.color
or uses '#000000'
cornersDotOptions: {
color: '#FF0000'
}
gradient
cornersSquareOptions.gradient
)Gradient
object (see Gradients)undefined
cornersDotOptions: {
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' }
color
string
(CSS color, hex, rgb, rgba)'#FFFFFF'
backgroundOptions: {
color: '#F5F5F5'
}
round
number
or string
0
backgroundOptions: {
round: 0.5
}
gradient
Gradient
object (see Gradients)undefined
backgroundOptions: {
gradient: {
type: 'linear',
rotation: Math.PI / 2,
colorStops: [{ offset: 0, color: '#eee' }, { offset: 1, color: '#ccc' }]
}
}
image
QRCodeJs.setImage()
for a global default, or QRCodeJs.useImage()
for a builder-specific image.string | Buffer | Blob
image: 'https://example.com/logo.png'
setImage
and useImage
setImage
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
});
imageOptions
Options for the embedded image.
mode
ImageMode
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'
}
imageSize
number
0.4
imageOptions: {
imageSize: 0.5
}
margin
number
0
imageOptions: {
margin: 2
}
crossOrigin
string
undefined
imageOptions: {
crossOrigin: 'anonymous'
}
fill
object
{ 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
, backgroundOptions
, and imageOptions.fill
.
object
type
: 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:
borderOptions
Options 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()
.
hasBorder
boolean
borderOptions: {
hasBorder: true
}
thickness
number
borderOptions: {
thickness: 50
}
color
string
(CSS color, hex, rgb, rgba)'#000000'
borderOptions: {
color: 'blue'
}
radius
string
(px or %)'0%'
borderOptions: {
radius: '40%'
}
noBorderThickness
number
borderOptions.thickness / 4
borderOptions: {
noBorderThickness: 5
}
background
string
(CSS color, hex, rgb, rgba)undefined
borderOptions: {
background: '#DDDDDD'
}
inner
object
radius
: 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
}
}
borderOuter
object
color
: Color of the outer border (string)thickness
: Thickness of the outer border (number)borderOptions: {
borderOuter: {
color: '#002683',
thickness: 10
}
}
borderInner
object
color
: Color of the inner border (string)thickness
: Thickness of the inner border (number)borderOptions: {
borderInner: {
color: 'yellow',
thickness: 5
}
}
decorations
object
top
, 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 QRCodeJs
textNameOrOptions
: 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 QRCodeJs
textId
: 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 }): QRCodeBuilder
textNameOrOptions
: 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 }): QRCodeBuilder
textId
: 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: true
All 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.