or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

accessibility.mdcolor-analysis.mdcolor-conversion.mdcolor-creation.mdcolor-modification.mdcolor-schemes.mdindex.mdutilities.md

accessibility.mddocs/

0

# Accessibility and Readability

1

2

Static methods for calculating color contrast ratios and determining readability according to WCAG (Web Content Accessibility Guidelines). These functions help ensure your color choices meet accessibility standards for users with visual impairments.

3

4

## Capabilities

5

6

### Contrast Ratio Calculation

7

8

#### Calculate Readability

9

10

Calculates the contrast ratio between two colors using WCAG formulas.

11

12

```javascript { .api }

13

/**

14

* Calculates the contrast ratio between two colors

15

* Uses WCAG formula: (L1 + 0.05) / (L2 + 0.05) where L1 is lighter, L2 is darker

16

* @param color1 - First color (any valid tinycolor input)

17

* @param color2 - Second color (any valid tinycolor input)

18

* @returns number representing contrast ratio (1-21, where 21 is maximum contrast)

19

*/

20

tinycolor.readability(color1: any, color2: any): number;

21

```

22

23

**Usage Examples:**

24

25

```javascript

26

import tinycolor from "tinycolor2";

27

28

// Calculate contrast ratios

29

const whiteBlack = tinycolor.readability("white", "black");

30

const whiteGray = tinycolor.readability("#ffffff", "#808080");

31

const blueWhite = tinycolor.readability("#0066cc", "white");

32

33

console.log("White/Black contrast:", whiteBlack); // 21 (maximum contrast)

34

console.log("White/Gray contrast:", whiteGray); // ~2.28

35

console.log("Blue/White contrast:", blueWhite); // ~4.89

36

37

// Check various background/text combinations

38

const backgrounds = ["#ffffff", "#f8f9fa", "#e9ecef", "#343a40", "#000000"];

39

const textColors = ["#000000", "#495057", "#6c757d", "#ffffff"];

40

41

backgrounds.forEach(bg => {

42

console.log(`Background: ${bg}`);

43

textColors.forEach(text => {

44

const ratio = tinycolor.readability(bg, text);

45

console.log(` Text ${text}: ${ratio.toFixed(2)}`);

46

});

47

});

48

```

49

50

### WCAG Compliance Testing

51

52

#### Test Readability Standards

53

54

Tests if two colors meet WCAG readability guidelines.

55

56

```javascript { .api }

57

/**

58

* Tests if color combination meets WCAG guidelines

59

* @param color1 - First color (any valid tinycolor input)

60

* @param color2 - Second color (any valid tinycolor input)

61

* @param wcag2 - WCAG parameters object (optional)

62

* @returns boolean indicating if combination meets standards

63

*/

64

tinycolor.isReadable(color1: any, color2: any, wcag2?: {level?: "AA" | "AAA", size?: "small" | "large"}): boolean;

65

```

66

67

**WCAG Standards:**

68

- **AA Large Text**: Contrast ratio ≥ 3:1

69

- **AA Normal Text**: Contrast ratio ≥ 4.5:1

70

- **AAA Large Text**: Contrast ratio ≥ 4.5:1

71

- **AAA Normal Text**: Contrast ratio ≥ 7:1

72

73

**Usage Examples:**

74

75

```javascript

76

// Test with default settings (AA level, small text)

77

const isReadable1 = tinycolor.isReadable("#000000", "#ffffff");

78

console.log("Black on white:", isReadable1); // true

79

80

const isReadable2 = tinycolor.isReadable("#777777", "#ffffff");

81

console.log("Gray on white:", isReadable2); // false (insufficient contrast)

82

83

// Test with specific WCAG levels

84

const combinations = [

85

{ bg: "#ffffff", text: "#000000" },

86

{ bg: "#ffffff", text: "#666666" },

87

{ bg: "#ffffff", text: "#999999" },

88

{ bg: "#2c3e50", text: "#ffffff" },

89

{ bg: "#3498db", text: "#ffffff" }

90

];

91

92

combinations.forEach(combo => {

93

const aaSmall = tinycolor.isReadable(combo.bg, combo.text, {level: "AA", size: "small"});

94

const aaLarge = tinycolor.isReadable(combo.bg, combo.text, {level: "AA", size: "large"});

95

const aaaSmall = tinycolor.isReadable(combo.bg, combo.text, {level: "AAA", size: "small"});

96

const aaaLarge = tinycolor.isReadable(combo.bg, combo.text, {level: "AAA", size: "large"});

97

98

console.log(`${combo.text} on ${combo.bg}:`);

99

console.log(` AA Small: ${aaSmall}, AA Large: ${aaLarge}`);

100

console.log(` AAA Small: ${aaaSmall}, AAA Large: ${aaaLarge}`);

101

});

102

103

// Validate user interface colors

104

function validateUIColors(backgroundColor, textColor, level = "AA") {

105

const tests = {

106

smallText: tinycolor.isReadable(backgroundColor, textColor, {level, size: "small"}),

107

largeText: tinycolor.isReadable(backgroundColor, textColor, {level, size: "large"}),

108

ratio: tinycolor.readability(backgroundColor, textColor)

109

};

110

111

return {

112

passes: tests.smallText,

113

passesLarge: tests.largeText,

114

ratio: tests.ratio,

115

level: level

116

};

117

}

118

```

119

120

### Find Most Readable Color

121

122

#### Find Optimal Text Color

123

124

Finds the most readable color from a list of options for a given background.

125

126

```javascript { .api }

127

/**

128

* Finds the most readable color from a list for the given background

129

* @param baseColor - Background color (any valid tinycolor input)

130

* @param colorList - Array of potential text colors

131

* @param args - Optional arguments object

132

* @returns tinycolor instance of the most readable color

133

*/

134

tinycolor.mostReadable(baseColor: any, colorList: any[], args?: {includeFallbackColors?: boolean, level?: "AA" | "AAA", size?: "small" | "large"}): tinycolor;

135

```

136

137

**Usage Examples:**

138

139

```javascript

140

// Find best text color for various backgrounds

141

const textOptions = ["#000000", "#333333", "#666666", "#999999", "#ffffff"];

142

143

const darkBg = "#2c3e50";

144

const lightBg = "#ecf0f1";

145

const colorfulBg = "#e74c3c";

146

147

const bestForDark = tinycolor.mostReadable(darkBg, textOptions);

148

const bestForLight = tinycolor.mostReadable(lightBg, textOptions);

149

const bestForColorful = tinycolor.mostReadable(colorfulBg, textOptions);

150

151

console.log("Best text for dark background:", bestForDark.toHexString());

152

console.log("Best text for light background:", bestForLight.toHexString());

153

console.log("Best text for colorful background:", bestForColorful.toHexString());

154

155

// With WCAG level requirements

156

const bestAAA = tinycolor.mostReadable("#3498db", ["#ffffff", "#000000"], {

157

level: "AAA",

158

size: "small"

159

});

160

161

// With fallback colors (includes black and white if needed)

162

const bestWithFallback = tinycolor.mostReadable("#ff6b6b", ["#ffcc02", "#06ffa5"], {

163

includeFallbackColors: true,

164

level: "AA"

165

});

166

167

// Smart text color selection

168

function getOptimalTextColor(backgroundColor, preferredColors = ["#000000", "#ffffff"]) {

169

const bgColor = tinycolor(backgroundColor);

170

171

// Start with preferred colors

172

let bestColor = tinycolor.mostReadable(bgColor, preferredColors);

173

174

// If no preferred color works, expand options

175

if (!tinycolor.isReadable(bgColor, bestColor)) {

176

const expandedOptions = [

177

"#000000", "#333333", "#666666", "#999999", "#cccccc", "#ffffff"

178

];

179

bestColor = tinycolor.mostReadable(bgColor, expandedOptions, {

180

includeFallbackColors: true

181

});

182

}

183

184

return bestColor.toHexString();

185

}

186

```

187

188

## Accessibility Workflows

189

190

### Comprehensive Accessibility Analysis

191

192

```javascript

193

function analyzeColorAccessibility(backgroundColor, textColor) {

194

const bgColor = tinycolor(backgroundColor);

195

const txtColor = tinycolor(textColor);

196

197

if (!bgColor.isValid() || !txtColor.isValid()) {

198

return { error: "Invalid color input" };

199

}

200

201

const ratio = tinycolor.readability(bgColor, txtColor);

202

203

const compliance = {

204

"AA-small": ratio >= 4.5,

205

"AA-large": ratio >= 3.0,

206

"AAA-small": ratio >= 7.0,

207

"AAA-large": ratio >= 4.5

208

};

209

210

const suggestions = [];

211

212

if (!compliance["AA-small"]) {

213

// Suggest better alternatives

214

const alternatives = ["#000000", "#ffffff"];

215

const better = tinycolor.mostReadable(bgColor, alternatives);

216

suggestions.push(`Try ${better.toHexString()} for better contrast`);

217

}

218

219

return {

220

ratio: ratio,

221

compliance: compliance,

222

suggestions: suggestions,

223

grade: compliance["AAA-small"] ? "AAA" :

224

compliance["AA-small"] ? "AA" :

225

compliance["AA-large"] ? "AA (large text only)" : "Fail"

226

};

227

}

228

229

// Usage

230

const analysis = analyzeColorAccessibility("#3498db", "#ffffff");

231

console.log(analysis);

232

```

233

234

### Design System Validation

235

236

```javascript

237

function validateDesignSystem(colorPalette) {

238

const results = {};

239

240

// Test all background/text combinations

241

Object.keys(colorPalette.backgrounds || {}).forEach(bgName => {

242

const bgColor = colorPalette.backgrounds[bgName];

243

results[bgName] = {};

244

245

Object.keys(colorPalette.text || {}).forEach(textName => {

246

const textColor = colorPalette.text[textName];

247

const ratio = tinycolor.readability(bgColor, textColor);

248

const isAA = tinycolor.isReadable(bgColor, textColor);

249

const isAAA = tinycolor.isReadable(bgColor, textColor, {level: "AAA"});

250

251

results[bgName][textName] = {

252

ratio: ratio,

253

AA: isAA,

254

AAA: isAAA,

255

status: isAAA ? "AAA" : isAA ? "AA" : "FAIL"

256

};

257

});

258

});

259

260

return results;

261

}

262

263

// Example color palette

264

const myPalette = {

265

backgrounds: {

266

primary: "#2c3e50",

267

secondary: "#3498db",

268

light: "#ecf0f1",

269

white: "#ffffff"

270

},

271

text: {

272

primary: "#2c3e50",

273

secondary: "#7f8c8d",

274

light: "#bdc3c7",

275

white: "#ffffff"

276

}

277

};

278

279

const validation = validateDesignSystem(myPalette);

280

```

281

282

### Automatic Color Adjustment

283

284

```javascript

285

function makeReadable(backgroundColor, textColor, targetLevel = "AA", targetSize = "small") {

286

const bgColor = tinycolor(backgroundColor);

287

let txtColor = tinycolor(textColor);

288

289

// If already readable, return as-is

290

if (tinycolor.isReadable(bgColor, txtColor, {level: targetLevel, size: targetSize})) {

291

return txtColor.toHexString();

292

}

293

294

// Try to adjust the text color to meet requirements

295

const bgLuminance = bgColor.getLuminance();

296

const shouldBeDark = bgLuminance > 0.5;

297

298

// Start with pure black or white based on background

299

const startColor = shouldBeDark ? "#000000" : "#ffffff";

300

let adjustedColor = tinycolor(startColor);

301

302

// If pure black/white doesn't work, gradually adjust towards original color

303

if (!tinycolor.isReadable(bgColor, adjustedColor, {level: targetLevel, size: targetSize})) {

304

// This is rare, but handle edge cases

305

const alternatives = ["#000000", "#ffffff", "#333333", "#cccccc"];

306

adjustedColor = tinycolor.mostReadable(bgColor, alternatives, {

307

includeFallbackColors: true,

308

level: targetLevel,

309

size: targetSize

310

});

311

}

312

313

return adjustedColor.toHexString();

314

}

315

316

// Usage

317

const readableText = makeReadable("#ff6b6b", "#ffcc02", "AA", "small");

318

console.log("Adjusted text color:", readableText);

319

```

320

321

### Color Blindness Considerations

322

323

```javascript

324

function checkColorBlindAccessibility(color1, color2) {

325

const c1 = tinycolor(color1);

326

const c2 = tinycolor(color2);

327

328

// Convert to different color spaces for analysis

329

const rgb1 = c1.toRgb();

330

const rgb2 = c2.toRgb();

331

332

// Simulate common color blindness types (simplified)

333

const protanopia = {

334

// Red-blind simulation (simplified)

335

color1: tinycolor({r: rgb1.g, g: rgb1.g, b: rgb1.b}),

336

color2: tinycolor({r: rgb2.g, g: rgb2.g, b: rgb2.b})

337

};

338

339

const deuteranopia = {

340

// Green-blind simulation (simplified)

341

color1: tinycolor({r: rgb1.r, g: rgb1.r, b: rgb1.b}),

342

color2: tinycolor({r: rgb2.r, g: rgb2.r, b: rgb2.b})

343

};

344

345

return {

346

normal: tinycolor.readability(c1, c2),

347

protanopia: tinycolor.readability(protanopia.color1, protanopia.color2),

348

deuteranopia: tinycolor.readability(deuteranopia.color1, deuteranopia.color2),

349

// Add tritanopia and other types as needed

350

};

351

}

352

```