A Javascript Design Pattern: Configuration Objects within an IIFE

Posted by admin
Tuesday April 7th , 2026 4:58 p.m.



 

 

 

/**
* @file
* My theme definitions for some widget.
*/
(function (window) {
'use strict';

window.MyThemes = {
THEMES: {
dark: {
skeletonColor: {
primary: '#F3F5FD',
secondary: '#FFFFFF'
},
fontFamily: 'Helvetica, Arial, sans-serif;',
palette: {
primary: { main: '#FAFAFA', dark: '#7a7a7a', light: '#EEE8E8' },
primaryContrast: { main: '#1A1A1A', dark: '#111214', light: '#1E1E1E' },
accent: { main: '#2A8C24', dark: '#662918', light: '#41AE3A' },
accentContrast: { main: '#FAFAFA', dark: '#dbd8d8', light: '#EEE8E8' },
secondary: { main: '#ffffff', dark: '#3b404d', light: '#5F5F5F' },
tertiary: { main: '#414042', dark: '#272b33', light: '#5F5F5F' },
green: { main: '#5FC046', dark: '#185926', light: '#83D36F' },
red: { main: '#ff0000', dark: '#803630', light: '#E54848' },
separator: {
primary: 'rgba(255,255,255,0.12)',
secondary: 'rgba(255,255,255,0.06)'
},
focus: '#3F9AF5',
autofill: '#2C302B'
},
background: {
base: '#000000',
notification: '#414042',
primary: { main: '#1A1A1A', dark: '#0e0e12', light: '#212121' },
secondary: { main: '#282828', dark: '#191b21', light: '#414042' },
tertiary: { main: '#2E2E2E', dark: '#23262e', light: '#5C5C5C' }
},
shadow: {
normal: '0px 4px 64px 0px #000',
small: '0px 4px 24px 0px rgba(0,0,0,0.64)'
}
},
light: {
skeletonColor: {
primary: '#E8ECF5',
secondary: '#F7F8FC'
},
fontFamily: 'Helvetica, Arial, sans-serif;',
palette: {
primary: { main: '#1A1A1A', dark: '#111111', light: '#333333' },
primaryContrast: { main: '#FAFAFA', dark: '#EEEEEE', light: '#FFFFFF' },
accent: { main: '#2A8C24', dark: '#1B5E20', light: '#41AE3A' },
accentContrast: { main: '#FFFFFF', dark: '#F5F5F5', light: '#FFFFFF' },
secondary: { main: '#333333', dark: '#1A1A1A', light: '#555555' },
tertiary: { main: '#666666', dark: '#444444', light: '#888888' },
green: { main: '#2E7D32', dark: '#1B5E20', light: '#43A047' },
red: { main: '#C62828', dark: '#8B0000', light: '#EF5350' },
separator: {
primary: 'rgba(0,0,0,0.12)',
secondary: 'rgba(0,0,0,0.06)'
},
focus: '#1565C0',
autofill: '#E8F5E9'
},
background: {
base: '#FFFFFF',
notification: '#F5F5F5',
primary: { main: '#FFFFFF', dark: '#F0F0F0', light: '#FAFAFA' },
secondary: { main: '#F5F5F5', dark: '#E8E8E8', light: '#FAFAFA' },
tertiary: { main: '#EEEEEE', dark: '#E0E0E0', light: '#F5F5F5' }
},
shadow: {
normal: '0px 4px 64px 0px rgba(0,0,0,0.15)',
small: '0px 4px 24px 0px rgba(0,0,0,0.10)'
}
}
},

SHARED: {
heatmapWidget: {
heatPalette: {
green: {
'1': '#9BE4AA',
'2': '#7EDC92',
'3': '#61D47A',
'4': '#45CD62',
'5': '#32BA50',
'6': '#2B9E43',
'7': '#238137',
'8': '#1B642B',
'9': '#13481F',
'10': '#0C2B12'
},
red: {
'1': '#FCB2A7',
'2': '#FA9484',
'3': '#F97561',
'4': '#E13030',
'5': '#F6381B',
'6': '#E42609',
'7': '#C12007',
'8': '#9E1A06',
'9': '#7B1405',
'10': '#580E03'
},
blue: {
'1': '#ABC0F7',
'2': '#8AA7F4',
'3': '#698EF1',
'4': '#4774EE',
'5': '#265BEB',
'6': '#1449D9',
'7': '#113EB8',
'8': '#0E3396',
'9': '#0B2775',
'10': '#081C54'
}
}
},
chartPalette: [
'rgba(249,157,153,1)',
'rgba(249,198,154,1)',
'rgba(246,224,155,1)',
'rgba(167,231,197,1)',
'rgba(151,199,245,1)',
'rgba(193,152,245,1)',
'rgba(233,162,234,1)',
'rgba(249,108,102,1)',
'rgba(249,171,105,1)',
'rgba(246,212,106,1)',
'rgba(97,231,160,1)',
'rgba(103,175,245,1)',
'rgba(166,103,245,1)',
'rgba(232,115,234,1)',
'rgba(249,60,52,1)',
'rgba(249,145,55,1)',
'rgba(246,200,57,1)',
'rgba(28,231,123,1)',
'rgba(54,151,245,1)',
'rgba(138,54,245,1)',
'rgba(232,68,234,1)',
'rgba(249,10,0,1)',
'rgba(249,118,5,1)',
'rgba(246,188,7,1)',
'rgba(0,247,116,1)',
'rgba(5,128,245,1)',
'rgba(111,5,245,1)',
'rgba(231,21,234,1)'
],
surfaceChartVisualMapPalette: [
'#FFFCA9',
'#FFCA85',
'#E34E37',
'#FB3D38'
],
eventViewerWidget: {
yellow: '#FCD405'
},
typography: {
header: {
'1': ['font-size: 42px; line-height: 50px; font-weight: 700;'],
'2': ['font-size: 32px; line-height: 38px; font-weight: 400;'],
'3': ['font-size: 26px; line-height: 36px; font-weight: 700;'],
'4': ['font-size: 20px; line-height: 26px; font-weight: 500;'],
'5': ['font-size: 16px; line-height: 28px; font-weight: 700;']
},
body: {
regular: {
'1': ['font-size: 18px; line-height: 24px; font-weight: 400;'],
'2': ['font-size: 16px; line-height: 20px; font-weight: 400;'],
'3': ['font-size: 14px; line-height: 18px; font-weight: 400;'],
'4': ['font-size: 12px; line-height: 16px; font-weight: 400;'],
'5': ['font-size: 13px; line-height: 16px; text-transform: uppercase; letter-spacing: 0.08em;']
},
medium: {
'1': ['font-size: 18px; line-height: 24px; font-weight: 500;'],
'2': ['font-size: 16px; line-height: 20px; font-weight: 500;'],
'3': ['font-size: 14px; line-height: 18px; font-weight: 500;']
}
},
bodyWide: {
regular: {
'1': ['font-size: 18px; line-height: 28px; font-weight: 400;'],
'2': ['font-size: 16px; line-height: 24px; font-weight: 400;'],
'3': ['font-size: 14px; line-height: 22px; font-weight: 400;'],
'4': ['font-size: 12px; line-height: 20px; font-weight: 400;']
},
medium: {
'1': ['font-size: 18px; line-height: 28px; font-weight: 500;'],
'2': ['font-size: 16px; line-height: 24px; font-weight: 500;'],
'3': ['font-size: 14px; line-height: 22px; font-weight: 500;']
}
}
},
zIndex: {
sticky: 10,
popover: 1000
},
borderRadius: {
small: '3px',
normal: '6px'
}
},

build(modeName) {
const mode = this.THEMES[modeName] || this.THEMES.dark;
return {
...this.SHARED,
...mode
};
}
};

})(window);


 


Yes — this code defines a reusable theme configuration object on window, and it wraps everything in an IIFE so it doesn’t leak temporary variables into the global scope. The build(modeName) function returns a merged theme object for either dark or light, using the selected theme plus shared settings.



This is an Immediately Invoked Function Expression (IIFE): a function that runs as soon as it is defined. It takes window as an argument and immediately calls itself with the browser’s global window object.

'use strict'; enables strict mode, which makes JavaScript use a stricter set of rules and catches more mistakes early.

The global variable it creates

Inside the function, this line attaches a property to the browser’s global window object:

window.MyThemes = { ... }

 

 

 

That means other scripts can later access this as window.MyThemes. This is a common pattern for exposing one public API while keeping everything else inside the closure.

Structure of the object

The object has three main parts:

  • THEMES: two complete theme definitions, dark and light.

  • SHARED: values reused by both themes.

  • build(modeName): a function that returns a combined theme object.

Each theme contains nested settings like palette, background, shadow, and fontFamily. These are just plain JavaScript objects grouping related style values together.


This function picks the requested theme by name. If modeName is missing or invalid, it falls back to dark. Then it returns a new object that combines SHARED and the selected theme.

The ... syntax is spread syntax. In an object literal, it copies properties from one object into a new object. If both objects have the same property name, the later one wins.

Important detail about merging

Because return { ...this.SHARED, ...mode } is a shallow merge, it copies top-level properties only. So palette, background, and other nested objects from mode replace any same-named top-level objects in SHARED, rather than deeply merging them.

That means the final result includes:

  • all shared values from SHARED, such as chartPalette, typography, and borderRadius.

  • all theme-specific values from either dark or light, such as palette, background, shadow, and skeletonColor.

Example usage


const theme = window.MyThemes.build('light');

it gets a single object containing the shared chart styling plus the light-mode colors and backgrounds. If it calls build('unknown'), it gets the dark theme instead.


Next we'll look at how it might be used and re-used in a simple Drupal Javascript, and go a step further to the hardcoded colors into a custom Drupal Config Form.