or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

css-framework.mdforms.mdindex.mdinteractive.mdlayout.mdmedia.mdnavigation.mdutilities.md

forms.mddocs/

0

# Form Components

1

2

Enhanced form controls and input components including text fields, selects, date/time pickers, autocomplete, file inputs, and form validation with Material Design styling and JavaScript functionality.

3

4

## Capabilities

5

6

### Text Fields and Textarea

7

8

Enhanced text inputs with floating labels, validation, and character counting.

9

10

```javascript { .api }

11

/**

12

* Global form utilities available on M object

13

*/

14

declare const M: {

15

/** Update all text field labels (call after dynamic content changes) */

16

updateTextFields(): void;

17

18

/** Validate individual form field */

19

validate_field(field: Element): boolean;

20

21

/** Auto-resize textarea to fit content */

22

textareaAutoResize(textarea: Element): void;

23

};

24

```

25

26

**HTML Structure and CSS Classes:**

27

28

```html

29

<!-- Basic text input -->

30

<div class="input-field">

31

<input id="first_name" type="text" class="validate">

32

<label for="first_name">First Name</label>

33

</div>

34

35

<!-- Textarea with character counter -->

36

<div class="input-field">

37

<textarea id="textarea1" class="materialize-textarea" data-length="120"></textarea>

38

<label for="textarea1">Message</label>

39

</div>

40

41

<!-- Input with icon -->

42

<div class="input-field">

43

<i class="material-icons prefix">account_circle</i>

44

<input id="icon_prefix" type="text" class="validate">

45

<label for="icon_prefix">Username</label>

46

</div>

47

48

<!-- Input with validation -->

49

<div class="input-field">

50

<input id="email" type="email" class="validate">

51

<label for="email">Email</label>

52

<span class="helper-text" data-error="Invalid email" data-success="Valid email">Enter your email</span>

53

</div>

54

```

55

56

### Character Counter

57

58

Automatic character counting for text inputs and textareas.

59

60

```javascript { .api }

61

/**

62

* Character counter component

63

* @param el - Input or textarea element with data-length attribute

64

* @param options - Configuration options (currently empty)

65

*/

66

class CharacterCounter {

67

constructor(el: Element, options?: {});

68

69

static init(els: Element | NodeList, options?: {}): CharacterCounter | CharacterCounter[];

70

static getInstance(el: Element): CharacterCounter;

71

static get defaults(): {};

72

73

/** Update character count display */

74

updateCounter(): void;

75

76

destroy(): void;

77

}

78

```

79

80

**Usage Examples:**

81

82

```html

83

<!-- Character counter via data attribute -->

84

<div class="input-field">

85

<input id="input_text" type="text" data-length="10">

86

<label for="input_text">Input text</label>

87

</div>

88

89

<div class="input-field">

90

<textarea id="textarea2" class="materialize-textarea" data-length="120"></textarea>

91

<label for="textarea2">Textarea</label>

92

</div>

93

```

94

95

```javascript

96

// Initialize character counters

97

const elems = document.querySelectorAll('input[data-length], textarea[data-length]');

98

M.CharacterCounter.init(elems);

99

100

// Manual update after programmatic changes

101

const instance = M.CharacterCounter.getInstance(document.getElementById('input_text'));

102

instance.updateCounter();

103

```

104

105

### Select Dropdown

106

107

Enhanced select dropdowns with search functionality and custom styling.

108

109

```javascript { .api }

110

/**

111

* Form select component (enhanced dropdown select)

112

* @param el - Select element

113

* @param options - Configuration options

114

*/

115

class FormSelect {

116

constructor(el: Element, options?: FormSelectOptions);

117

118

static init(els: Element | NodeList, options?: FormSelectOptions): FormSelect | FormSelect[];

119

static getInstance(el: Element): FormSelect;

120

static get defaults(): FormSelectOptions;

121

122

/** Get array of selected values */

123

getSelectedValues(): string[];

124

125

destroy(): void;

126

}

127

128

interface FormSelectOptions {

129

/** Additional CSS classes for dropdown */

130

classes?: string;

131

132

/** Options to pass to underlying Dropdown component */

133

dropdownOptions?: {

134

alignment?: 'left' | 'right';

135

autoFocus?: boolean;

136

constrainWidth?: boolean;

137

container?: Element;

138

coverTrigger?: boolean;

139

closeOnClick?: boolean;

140

hover?: boolean;

141

inDuration?: number;

142

outDuration?: number;

143

};

144

}

145

```

146

147

**Usage Examples:**

148

149

```html

150

<!-- Basic select -->

151

<div class="input-field">

152

<select>

153

<option value="" disabled selected>Choose your option</option>

154

<option value="1">Option 1</option>

155

<option value="2">Option 2</option>

156

<option value="3">Option 3</option>

157

</select>

158

<label>Materialize Select</label>

159

</div>

160

161

<!-- Multiple select -->

162

<div class="input-field">

163

<select multiple>

164

<option value="" disabled selected>Choose your options</option>

165

<option value="1">Option 1</option>

166

<option value="2">Option 2</option>

167

<option value="3">Option 3</option>

168

</select>

169

<label>Multiple Select</label>

170

</div>

171

172

<!-- Select with icons -->

173

<div class="input-field">

174

<select>

175

<option value="" disabled selected>Choose your option</option>

176

<option value="1" data-icon="images/sample-1.jpg" class="left circle">Option 1</option>

177

<option value="2" data-icon="images/sample-2.jpg" class="left circle">Option 2</option>

178

</select>

179

<label>Select with Icons</label>

180

</div>

181

```

182

183

```javascript

184

// Initialize select dropdowns

185

const elems = document.querySelectorAll('select');

186

const instances = M.FormSelect.init(elems);

187

188

// Get selected values

189

const instance = M.FormSelect.getInstance(document.querySelector('select'));

190

const selectedValues = instance.getSelectedValues();

191

console.log('Selected:', selectedValues);

192

```

193

194

### Datepicker

195

196

Date selection component with calendar interface and internationalization support.

197

198

```javascript { .api }

199

/**

200

* Datepicker component

201

* @param el - Input element for date selection

202

* @param options - Configuration options

203

*/

204

class Datepicker {

205

constructor(el: Element, options?: DatepickerOptions);

206

207

static init(els: Element | NodeList, options?: DatepickerOptions): Datepicker | Datepicker[];

208

static getInstance(el: Element): Datepicker;

209

static get defaults(): DatepickerOptions;

210

211

/** Open datepicker */

212

open(): void;

213

214

/** Close datepicker */

215

close(): void;

216

217

/** Set selected date programmatically */

218

setDate(date?: Date): void;

219

220

/** Update input value from selected date */

221

setInputValue(): void;

222

223

/** Navigate to specific date */

224

gotoDate(date: Date): void;

225

226

destroy(): void;

227

}

228

229

interface DatepickerOptions {

230

/** Automatically close picker when date is selected */

231

autoClose?: boolean; // default: false

232

233

/** Date format for display */

234

format?: string; // default: 'mmm dd, yyyy'

235

236

/** Custom parse function for date strings */

237

parse?: (value: string, format: string) => Date;

238

239

/** Default date to show */

240

defaultDate?: Date;

241

242

/** Set default date as selected */

243

setDefaultDate?: boolean; // default: false

244

245

/** Disable weekends */

246

disableWeekends?: boolean; // default: false

247

248

/** Custom function to disable specific dates */

249

disableDayFn?: (date: Date) => boolean;

250

251

/** First day of week (0 = Sunday) */

252

firstDay?: number; // default: 0

253

254

/** Minimum selectable date */

255

minDate?: Date;

256

257

/** Maximum selectable date */

258

maxDate?: Date;

259

260

/** Year range for year selector */

261

yearRange?: number; // default: 10

262

263

/** Show clear button */

264

showClearBtn?: boolean; // default: false

265

266

/** Show month after year in title */

267

showMonthAfterYear?: boolean; // default: false

268

269

/** Show days of adjacent months */

270

showDaysInNextAndPreviousMonths?: boolean; // default: false

271

272

/** Container for datepicker modal */

273

container?: Element;

274

275

/** Internationalization options */

276

i18n?: {

277

cancel?: string;

278

clear?: string;

279

done?: string;

280

previousMonth?: string;

281

nextMonth?: string;

282

months?: string[];

283

monthsShort?: string[];

284

weekdays?: string[];

285

weekdaysShort?: string[];

286

weekdaysAbbrev?: string[];

287

};

288

289

/** Callbacks */

290

onSelect?: (date: Date) => void;

291

onOpen?: () => void;

292

onClose?: () => void;

293

onDraw?: () => void;

294

}

295

```

296

297

**Usage Examples:**

298

299

```html

300

<!-- Basic datepicker -->

301

<div class="input-field">

302

<input type="text" class="datepicker">

303

<label for="birthdate">Birthdate</label>

304

</div>

305

```

306

307

```javascript

308

// Initialize datepickers

309

const elems = document.querySelectorAll('.datepicker');

310

const instances = M.Datepicker.init(elems, {

311

format: 'yyyy-mm-dd',

312

autoClose: true,

313

minDate: new Date(2020, 0, 1), // January 1, 2020

314

maxDate: new Date(2025, 11, 31), // December 31, 2025

315

onSelect: (date) => console.log('Date selected:', date)

316

});

317

318

// Programmatic date setting

319

const instance = M.Datepicker.getInstance(document.querySelector('.datepicker'));

320

instance.setDate(new Date(2023, 5, 15)); // June 15, 2023

321

```

322

323

### Timepicker

324

325

Time selection component with clock interface and customizable options.

326

327

```javascript { .api }

328

/**

329

* Timepicker component

330

* @param el - Input element for time selection

331

* @param options - Configuration options

332

*/

333

class Timepicker {

334

constructor(el: Element, options?: TimepickerOptions);

335

336

static init(els: Element | NodeList, options?: TimepickerOptions): Timepicker | Timepicker[];

337

static getInstance(el: Element): Timepicker;

338

static get defaults(): TimepickerOptions;

339

340

/** Open timepicker */

341

open(): void;

342

343

/** Close timepicker */

344

close(): void;

345

346

destroy(): void;

347

}

348

349

interface TimepickerOptions {

350

/** Animation duration */

351

duration?: number; // default: 350

352

353

/** Container selector */

354

container?: string; // default: 'body'

355

356

/** Show clear button */

357

showClearBtn?: boolean; // default: false

358

359

/** Default time */

360

defaultTime?: string; // default: 'now'

361

362

/** Minutes from now as default time */

363

fromNow?: number; // default: 0

364

365

/** Internationalization */

366

i18n?: {

367

cancel?: string;

368

clear?: string;

369

done?: string;

370

};

371

372

/** Auto close on time selection */

373

autoClose?: boolean; // default: false

374

375

/** Use 12-hour format */

376

twelveHour?: boolean; // default: true

377

378

/** Vibrate on touch (mobile) */

379

vibrate?: boolean; // default: true

380

381

/** Callbacks */

382

onOpenStart?: () => void;

383

onOpenEnd?: () => void;

384

onCloseStart?: () => void;

385

onCloseEnd?: () => void;

386

onSelect?: (hour: number, minute: number) => void;

387

}

388

```

389

390

**Usage Examples:**

391

392

```html

393

<!-- Basic timepicker -->

394

<div class="input-field">

395

<input type="text" class="timepicker">

396

<label for="appt-time">Appointment Time</label>

397

</div>

398

```

399

400

```javascript

401

// Initialize timepickers

402

const elems = document.querySelectorAll('.timepicker');

403

const instances = M.Timepicker.init(elems, {

404

twelveHour: false, // 24-hour format

405

autoClose: true,

406

onSelect: (hour, minute) => console.log(`Time: ${hour}:${minute}`)

407

});

408

```

409

410

### Autocomplete

411

412

Autocomplete input with customizable data sources and filtering.

413

414

```javascript { .api }

415

/**

416

* Autocomplete component

417

* @param el - Input element

418

* @param options - Configuration options

419

*/

420

class Autocomplete {

421

constructor(el: Element, options?: AutocompleteOptions);

422

423

static init(els: Element | NodeList, options?: AutocompleteOptions): Autocomplete | Autocomplete[];

424

static getInstance(el: Element): Autocomplete;

425

static get defaults(): AutocompleteOptions;

426

427

/** Select option programmatically */

428

selectOption(el: Element): void;

429

430

/** Open autocomplete dropdown */

431

open(): void;

432

433

/** Close autocomplete dropdown */

434

close(): void;

435

436

/** Update autocomplete data */

437

updateData(data: { [key: string]: string | null }): void;

438

439

destroy(): void;

440

}

441

442

interface AutocompleteOptions {

443

/** Data object for autocomplete */

444

data?: { [key: string]: string | null }; // key: display text, value: image URL or null

445

446

/** Limit number of results */

447

limit?: number; // default: Infinity

448

449

/** Callback when autocomplete selection is made */

450

onAutocomplete?: (text: string) => void;

451

452

/** Minimum characters before autocomplete activates */

453

minLength?: number; // default: 1

454

455

/** Custom sort function for results */

456

sortFunction?: (a: string, b: string, inputString: string) => number;

457

}

458

```

459

460

**Usage Examples:**

461

462

```html

463

<!-- Autocomplete input -->

464

<div class="input-field">

465

<input type="text" id="autocomplete-input" class="autocomplete">

466

<label for="autocomplete-input">Autocomplete</label>

467

</div>

468

```

469

470

```javascript

471

// Initialize autocomplete

472

const elems = document.querySelectorAll('.autocomplete');

473

const instances = M.Autocomplete.init(elems, {

474

data: {

475

"Apple": null,

476

"Microsoft": null,

477

"Google": "https://placehold.it/250x250",

478

"Amazon": null,

479

"Facebook": null

480

},

481

limit: 5,

482

onAutocomplete: (val) => console.log('Autocomplete value:', val)

483

});

484

485

// Update data dynamically

486

const instance = M.Autocomplete.getInstance(document.getElementById('autocomplete-input'));

487

instance.updateData({

488

"New Item 1": null,

489

"New Item 2": "https://example.com/image.jpg"

490

});

491

```

492

493

### Chips

494

495

Chip input component for tags and multi-value inputs.

496

497

```javascript { .api }

498

/**

499

* Chips component for tag input

500

* @param el - Chips container element

501

* @param options - Configuration options

502

*/

503

class Chips {

504

constructor(el: Element, options?: ChipsOptions);

505

506

static init(els: Element | NodeList, options?: ChipsOptions): Chips | Chips[];

507

static getInstance(el: Element): Chips;

508

static get defaults(): ChipsOptions;

509

510

/** Get chips data */

511

getData(): ChipData[];

512

513

/** Add chip */

514

addChip(chip: ChipData): void;

515

516

/** Delete chip by index */

517

deleteChip(chipIndex: number): void;

518

519

/** Select chip by index */

520

selectChip(chipIndex: number): void;

521

522

destroy(): void;

523

}

524

525

interface ChipData {

526

tag: string;

527

image?: string;

528

}

529

530

interface ChipsOptions {

531

/** Initial chip data */

532

data?: ChipData[];

533

534

/** Placeholder text */

535

placeholder?: string;

536

537

/** Secondary placeholder text */

538

secondaryPlaceholder?: string;

539

540

/** Autocomplete options */

541

autocompleteOptions?: AutocompleteOptions;

542

543

/** Maximum number of chips */

544

limit?: number; // default: Infinity

545

546

/** Callbacks */

547

onChipAdd?: (element: Element, chip: Element) => void;

548

onChipSelect?: (element: Element, chip: Element) => void;

549

onChipDelete?: (element: Element, chip: Element) => void;

550

}

551

```

552

553

**Usage Examples:**

554

555

```html

556

<!-- Basic chips -->

557

<div class="chips"></div>

558

559

<!-- Chips with initial data -->

560

<div class="chips chips-initial"></div>

561

562

<!-- Chips with placeholder -->

563

<div class="chips chips-placeholder"></div>

564

```

565

566

```javascript

567

// Initialize chips

568

const elems = document.querySelectorAll('.chips');

569

M.Chips.init(elems);

570

571

// Chips with initial data

572

const chipInitial = document.querySelector('.chips-initial');

573

M.Chips.init(chipInitial, {

574

data: [

575

{ tag: 'Apple' },

576

{ tag: 'Microsoft' },

577

{ tag: 'Google' }

578

]

579

});

580

581

// Chips with placeholder and autocomplete

582

const chipPlaceholder = document.querySelector('.chips-placeholder');

583

M.Chips.init(chipPlaceholder, {

584

placeholder: 'Enter a tag',

585

secondaryPlaceholder: '+Tag',

586

autocompleteOptions: {

587

data: {

588

'JavaScript': null,

589

'TypeScript': null,

590

'Python': null,

591

'Java': null

592

}

593

}

594

});

595

596

// Get chip data

597

const instance = M.Chips.getInstance(chipPlaceholder);

598

const chipData = instance.getData();

599

console.log('Current chips:', chipData);

600

```

601

602

### Range Slider

603

604

Enhanced range input with Material Design styling.

605

606

```javascript { .api }

607

/**

608

* Range slider component

609

* @param el - Input range element

610

* @param options - Configuration options (currently empty)

611

*/

612

class Range {

613

constructor(el: Element, options?: {});

614

615

static init(els: Element | NodeList, options?: {}): Range | Range[];

616

static getInstance(el: Element): Range;

617

static get defaults(): {};

618

619

destroy(): void;

620

}

621

```

622

623

**Usage Examples:**

624

625

```html

626

<!-- Basic range slider -->

627

<form action="#">

628

<p class="range-field">

629

<input type="range" id="test5" min="0" max="100" />

630

</p>

631

</form>

632

```

633

634

```javascript

635

// Initialize range sliders

636

const elems = document.querySelectorAll('input[type=range]');

637

M.Range.init(elems);

638

```

639

640

## Form Validation

641

642

### CSS Validation Classes

643

644

```css { .api }

645

/* Validation states */

646

.valid {

647

/* Applied to valid inputs */

648

border-bottom: 1px solid #4CAF50;

649

box-shadow: 0 1px 0 0 #4CAF50;

650

}

651

652

.invalid {

653

/* Applied to invalid inputs */

654

border-bottom: 1px solid #F44336;

655

box-shadow: 0 1px 0 0 #F44336;

656

}

657

658

/* Helper text */

659

.helper-text {

660

/* Helper text styling */

661

font-size: 0.8rem;

662

color: rgba(0,0,0,0.54);

663

}

664

665

.helper-text.invalid {

666

/* Error message styling */

667

color: #F44336;

668

}

669

```

670

671

### JavaScript Validation

672

673

```javascript

674

// Manual field validation

675

const emailField = document.getElementById('email');

676

const isValid = M.validate_field(emailField);

677

678

// Update all text fields (useful after AJAX content)

679

M.updateTextFields();

680

681

// Custom validation function

682

function validateForm(form) {

683

let isValid = true;

684

const inputs = form.querySelectorAll('input[type="text"], input[type="email"]');

685

686

inputs.forEach(input => {

687

if (!M.validate_field(input)) {

688

isValid = false;

689

}

690

});

691

692

return isValid;

693

}

694

```

695

696

## Common Form Patterns

697

698

### Dynamic Form Updates

699

700

```javascript

701

// After adding form elements dynamically

702

M.updateTextFields();

703

M.FormSelect.init(document.querySelectorAll('select'));

704

M.CharacterCounter.init(document.querySelectorAll('input[data-length], textarea[data-length]'));

705

706

// Reinitialize specific components

707

const newDatepickers = document.querySelectorAll('.datepicker:not([data-select-id])');

708

M.Datepicker.init(newDatepickers);

709

```

710

711

### Form Submission Handling

712

713

```javascript

714

document.getElementById('myForm').addEventListener('submit', function(e) {

715

e.preventDefault();

716

717

// Validate all fields

718

const inputs = this.querySelectorAll('input.validate');

719

let allValid = true;

720

721

inputs.forEach(input => {

722

if (!M.validate_field(input)) {

723

allValid = false;

724

}

725

});

726

727

if (allValid) {

728

// Process form submission

729

const formData = new FormData(this);

730

console.log('Form is valid, submitting...', formData);

731

} else {

732

M.toast({html: 'Please fix validation errors'});

733

}

734

});

735

```