or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-updates.mdevent-handling.mdindex.mdslider-creation.mdui-enhancements.mdvalue-management.md

ui-enhancements.mddocs/

0

# UI Enhancements

1

2

Additional UI features including tooltips, scale markers (pips), styling customization, and advanced interaction capabilities.

3

4

## Capabilities

5

6

### Pips (Scale Markers)

7

8

Scale markers that provide visual reference points along the slider track.

9

10

#### pips()

11

12

Adds or updates scale markers on the slider.

13

14

```javascript { .api }

15

/**

16

* Add or update scale markers (pips) on the slider

17

* @param config - Pips configuration object

18

* @returns HTML element containing the pips

19

*/

20

slider.noUiSlider.pips(config: PipsConfig): HTMLElement;

21

22

interface PipsConfig {

23

mode: 'range' | 'steps' | 'positions' | 'count' | 'values';

24

values?: number[];

25

stepped?: boolean;

26

density?: number;

27

filter?: (value: number, type: number) => number;

28

format?: Formatter;

29

}

30

```

31

32

#### removePips()

33

34

Removes all scale markers from the slider.

35

36

```javascript { .api }

37

/**

38

* Remove all scale markers from the slider

39

*/

40

slider.noUiSlider.removePips(): void;

41

```

42

43

**Usage Examples:**

44

45

```javascript

46

// Basic pips using range mode

47

slider.noUiSlider.pips({

48

mode: 'range',

49

density: 3

50

});

51

52

// Count mode - specific number of markers

53

slider.noUiSlider.pips({

54

mode: 'count',

55

values: 5, // 5 evenly spaced markers

56

density: 2

57

});

58

59

// Positions mode - markers at specific percentages

60

slider.noUiSlider.pips({

61

mode: 'positions',

62

values: [0, 25, 50, 75, 100],

63

density: 4

64

});

65

66

// Values mode - markers at specific values

67

slider.noUiSlider.pips({

68

mode: 'values',

69

values: [10, 25, 50, 75, 90],

70

density: 3

71

});

72

73

// Steps mode - markers at step intervals

74

slider.noUiSlider.pips({

75

mode: 'steps',

76

density: 2,

77

stepped: true

78

});

79

80

// Remove pips

81

slider.noUiSlider.removePips();

82

```

83

84

### Pips Configuration Options

85

86

#### mode

87

Determines how pip positions are calculated.

88

89

- `'range'`: Distribute pips evenly across the range

90

- `'steps'`: Place pips at step intervals

91

- `'positions'`: Place pips at specific percentage positions

92

- `'count'`: Place a specific number of evenly distributed pips

93

- `'values'`: Place pips at specific values

94

95

#### values

96

Array of values or positions (usage depends on mode).

97

98

```javascript

99

// For 'positions' mode: percentage positions

100

values: [0, 25, 50, 75, 100]

101

102

// For 'values' mode: actual slider values

103

values: [100, 500, 1000, 2000]

104

105

// For 'count' mode: number of pips

106

values: 6 // or as single number

107

```

108

109

#### density

110

Controls spacing and visibility of pips.

111

112

```javascript

113

// Higher density = more pips shown

114

density: 1 // Show every pip

115

density: 2 // Show every other pip

116

density: 4 // Show every fourth pip

117

```

118

119

#### stepped

120

Whether to align pips to step values (for 'range' and 'steps' modes).

121

122

```javascript

123

stepped: true // Align to steps

124

stepped: false // Use exact positions

125

```

126

127

#### filter

128

Function to customize which pips are displayed.

129

130

```javascript { .api }

131

filter?: (value: number, type: number) => number;

132

133

// Type values:

134

// -1: No pip

135

// 0: Normal pip

136

// 1: Large pip

137

// 2: Sub pip

138

```

139

140

```javascript

141

// Custom filter example

142

slider.noUiSlider.pips({

143

mode: 'range',

144

density: 2,

145

filter: function(value, type) {

146

// Hide pips for odd values

147

if (value % 2 === 1) {

148

return -1; // No pip

149

}

150

151

// Large pips for multiples of 10

152

if (value % 10 === 0) {

153

return 1; // Large pip

154

}

155

156

return 0; // Normal pip

157

}

158

});

159

```

160

161

#### format

162

Custom formatting for pip labels.

163

164

```javascript

165

slider.noUiSlider.pips({

166

mode: 'count',

167

values: 5,

168

format: {

169

to: function(value) {

170

return '$' + Math.round(value);

171

}

172

}

173

});

174

```

175

176

### Tooltips

177

178

Dynamic value display attached to slider handles.

179

180

#### Tooltip Configuration

181

182

Set during slider creation or via updateOptions.

183

184

```javascript { .api }

185

tooltips?: boolean | Formatter | (boolean | Formatter)[];

186

```

187

188

#### removeTooltips()

189

190

Removes all tooltips from the slider.

191

192

```javascript { .api }

193

/**

194

* Remove all tooltips from the slider

195

*/

196

slider.noUiSlider.removeTooltips(): void;

197

```

198

199

#### getTooltips()

200

201

Returns array of tooltip elements.

202

203

```javascript { .api }

204

/**

205

* Get array of tooltip DOM elements

206

* @returns Array of tooltip elements (null for handles without tooltips)

207

*/

208

slider.noUiSlider.getTooltips(): HTMLElement[];

209

```

210

211

**Usage Examples:**

212

213

```javascript

214

// Enable default tooltips

215

noUiSlider.create(element, {

216

start: [20, 80],

217

range: { min: 0, max: 100 },

218

tooltips: true

219

});

220

221

// Custom tooltip formatting

222

noUiSlider.create(element, {

223

start: [1000, 3000],

224

range: { min: 0, max: 5000 },

225

tooltips: {

226

to: function(value) {

227

return '$' + Math.round(value).toLocaleString();

228

}

229

}

230

});

231

232

// Per-handle tooltip configuration

233

noUiSlider.create(element, {

234

start: [20, 50, 80],

235

range: { min: 0, max: 100 },

236

tooltips: [

237

true, // Default tooltip for first handle

238

false, // No tooltip for second handle

239

{ to: value => value.toFixed(1) + '%' } // Custom for third handle

240

]

241

});

242

243

// Access and modify tooltips

244

const tooltips = slider.noUiSlider.getTooltips();

245

tooltips[0].style.backgroundColor = 'red';

246

247

// Remove tooltips

248

slider.noUiSlider.removeTooltips();

249

```

250

251

### Handle Management

252

253

Access to slider handle elements for advanced customization.

254

255

#### getOrigins()

256

257

Returns array of handle origin elements.

258

259

```javascript { .api }

260

/**

261

* Get array of handle origin DOM elements

262

* @returns Array of handle origin elements

263

*/

264

slider.noUiSlider.getOrigins(): HTMLElement[];

265

```

266

267

**Usage Examples:**

268

269

```javascript

270

// Get handle elements

271

const handles = slider.noUiSlider.getOrigins();

272

273

// Customize handle appearance

274

handles[0].style.backgroundColor = 'red';

275

handles[1].style.backgroundColor = 'blue';

276

277

// Add custom event listeners to handles

278

handles.forEach((handle, index) => {

279

handle.addEventListener('mouseenter', function() {

280

console.log('Hovering over handle', index);

281

});

282

});

283

284

// Add custom content to handles

285

handles[0].innerHTML = '<span class="handle-label">Min</span>';

286

handles[1].innerHTML = '<span class="handle-label">Max</span>';

287

```

288

289

## Advanced Styling

290

291

### CSS Classes

292

293

Access to default CSS classes for styling customization.

294

295

```javascript { .api }

296

noUiSlider.cssClasses: CSSClasses;

297

```

298

299

**Usage Examples:**

300

301

```javascript

302

// Access default CSS classes

303

console.log(noUiSlider.cssClasses.handle); // "handle"

304

console.log(noUiSlider.cssClasses.connect); // "connect"

305

306

// Use for custom styling

307

const handleClass = 'noUi-' + noUiSlider.cssClasses.handle;

308

document.querySelectorAll('.' + handleClass).forEach(handle => {

309

handle.style.borderRadius = '50%';

310

});

311

```

312

313

### Custom CSS Classes

314

315

Override default CSS classes during creation.

316

317

```javascript

318

noUiSlider.create(element, {

319

start: [20, 80],

320

range: { min: 0, max: 100 },

321

cssPrefix: 'custom-',

322

cssClasses: {

323

target: 'slider',

324

base: 'slider-base',

325

handle: 'slider-handle',

326

connect: 'slider-connect'

327

}

328

});

329

```

330

331

### Target Element Access

332

333

#### target Property

334

335

Reference to the original DOM element.

336

337

```javascript { .api }

338

/**

339

* Reference to the slider's target DOM element

340

*/

341

slider.noUiSlider.target: HTMLElement;

342

```

343

344

**Usage Examples:**

345

346

```javascript

347

// Access target element

348

const targetElement = slider.noUiSlider.target;

349

350

// Add custom classes

351

targetElement.classList.add('premium-slider');

352

353

// Custom styling

354

targetElement.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)';

355

356

// Data attributes

357

targetElement.setAttribute('data-slider-id', 'price-range');

358

```

359

360

## Practical UI Enhancement Patterns

361

362

### Custom Pip Labels

363

364

```javascript

365

// Currency pips with custom labels

366

slider.noUiSlider.pips({

367

mode: 'values',

368

values: [0, 1000, 2500, 5000, 10000],

369

format: {

370

to: function(value) {

371

if (value >= 1000) {

372

return '$' + (value / 1000) + 'k';

373

}

374

return '$' + value;

375

}

376

},

377

filter: function(value, type) {

378

// Large pips for major values

379

if ([0, 5000, 10000].includes(value)) {

380

return 1; // Large pip

381

}

382

return 0; // Normal pip

383

}

384

});

385

```

386

387

### Interactive Tooltips

388

389

```javascript

390

// Create slider with tooltips

391

noUiSlider.create(element, {

392

start: [20, 80],

393

range: { min: 0, max: 100 },

394

tooltips: true,

395

connect: true

396

});

397

398

// Enhance tooltips with click handlers

399

const tooltips = slider.noUiSlider.getTooltips();

400

tooltips.forEach((tooltip, index) => {

401

if (tooltip) {

402

tooltip.addEventListener('click', function() {

403

const newValue = prompt('Enter new value:');

404

if (newValue !== null) {

405

slider.noUiSlider.setHandle(index, parseFloat(newValue));

406

}

407

});

408

409

tooltip.style.cursor = 'pointer';

410

tooltip.title = 'Click to edit value';

411

}

412

});

413

```

414

415

### Dynamic Pip Updates

416

417

```javascript

418

// Update pips based on zoom level

419

function updatePipsForZoom(zoomLevel) {

420

const pipConfigs = {

421

1: { mode: 'count', values: 5, density: 2 },

422

2: { mode: 'count', values: 10, density: 3 },

423

3: { mode: 'range', density: 1 }

424

};

425

426

slider.noUiSlider.removePips();

427

slider.noUiSlider.pips(pipConfigs[zoomLevel]);

428

}

429

430

// Zoom controls

431

document.getElementById('zoom-in').addEventListener('click', () => {

432

currentZoom = Math.min(3, currentZoom + 1);

433

updatePipsForZoom(currentZoom);

434

});

435

```

436

437

### Handle Labeling

438

439

```javascript

440

// Add persistent labels to handles

441

const handles = slider.noUiSlider.getOrigins();

442

const labels = ['Minimum', 'Maximum'];

443

444

handles.forEach((handle, index) => {

445

const label = document.createElement('div');

446

label.className = 'handle-label';

447

label.textContent = labels[index];

448

label.style.position = 'absolute';

449

label.style.top = '-30px';

450

label.style.left = '50%';

451

label.style.transform = 'translateX(-50%)';

452

label.style.fontSize = '12px';

453

label.style.fontWeight = 'bold';

454

455

handle.appendChild(label);

456

});

457

```

458

459

### Progress Indication

460

461

```javascript

462

// Visual progress indicator

463

function updateProgress() {

464

const values = slider.noUiSlider.get();

465

const progress = parseFloat(values[0]); // Use first handle

466

const maxValue = slider.noUiSlider.options.range.max;

467

const percentage = (progress / maxValue) * 100;

468

469

// Update progress bar

470

document.getElementById('progress-bar').style.width = percentage + '%';

471

472

// Update progress text

473

document.getElementById('progress-text').textContent =

474

Math.round(percentage) + '% Complete';

475

}

476

477

slider.noUiSlider.on('update', updateProgress);

478

```

479

480

### Conditional Styling

481

482

```javascript

483

// Style based on values

484

function updateSliderStyling(values) {

485

const range = parseFloat(values[1]) - parseFloat(values[0]);

486

const target = slider.noUiSlider.target;

487

488

// Remove previous state classes

489

target.classList.remove('narrow-range', 'wide-range', 'full-range');

490

491

// Add appropriate class based on range

492

if (range < 20) {

493

target.classList.add('narrow-range');

494

} else if (range > 80) {

495

target.classList.add('wide-range');

496

} else if (range === 100) {

497

target.classList.add('full-range');

498

}

499

}

500

501

slider.noUiSlider.on('update', function(values) {

502

updateSliderStyling(values);

503

});

504

```

505

506

## Accessibility Enhancements

507

508

```javascript

509

// Enhance accessibility

510

const handles = slider.noUiSlider.getOrigins();

511

handles.forEach((handle, index) => {

512

const handleElement = handle.querySelector('.noUi-handle');

513

514

// Custom aria labels

515

handleElement.setAttribute('aria-label', `Handle ${index + 1}`);

516

517

// Descriptive titles

518

handleElement.setAttribute('title', `Drag to adjust value ${index + 1}`);

519

});

520

521

// Update aria-valuetext with formatted values

522

slider.noUiSlider.on('update', function(values, handle) {

523

const handleElement = handles[handle].querySelector('.noUi-handle');

524

handleElement.setAttribute('aria-valuetext',

525

`Current value: ${values[handle]}`);

526

});

527

```