or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-management.mddata-display-components.mdfeedback-components.mdform-components.mdindex.mdlayout-components.mdnavigation-components.mdvisual-effects.md

layout-components.mddocs/

0

# Layout Components

1

2

Structural components for application layout including headers, drawers, navigation, tabs, and responsive grid systems. These components provide the foundation for Material Design app structures with responsive behavior and navigation patterns.

3

4

## Capabilities

5

6

### Material Layout

7

8

Main layout component that provides app structure with header, drawer, and content areas.

9

10

```javascript { .api }

11

/**

12

* Material Design layout component

13

* CSS Class: mdl-js-layout

14

* Widget: false

15

*/

16

interface MaterialLayout {

17

/** Toggle drawer open/closed state */

18

toggleDrawer(): void;

19

}

20

```

21

22

**HTML Structure:**

23

24

```html

25

<!-- Basic layout with header and drawer -->

26

<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">

27

<header class="mdl-layout__header">

28

<div class="mdl-layout__header-row">

29

<!-- Title -->

30

<span class="mdl-layout-title">Title</span>

31

<!-- Add spacer, to align navigation to the right -->

32

<div class="mdl-layout-spacer"></div>

33

<!-- Navigation. We hide it in small screens. -->

34

<nav class="mdl-navigation mdl-layout--large-screen-only">

35

<a class="mdl-navigation__link" href="">Link</a>

36

<a class="mdl-navigation__link" href="">Link</a>

37

</nav>

38

</div>

39

</header>

40

41

<div class="mdl-layout__drawer">

42

<span class="mdl-layout-title">Title</span>

43

<nav class="mdl-navigation">

44

<a class="mdl-navigation__link" href="">Link</a>

45

<a class="mdl-navigation__link" href="">Link</a>

46

</nav>

47

</div>

48

49

<main class="mdl-layout__content">

50

<div class="page-content">

51

<!-- Your content goes here -->

52

</div>

53

</main>

54

</div>

55

```

56

57

**Layout Modes:**

58

59

```html

60

<!-- Fixed header that stays at top during scroll -->

61

<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">

62

63

<!-- Fixed drawer that stays open on large screens -->

64

<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer">

65

66

<!-- Waterfall header that shrinks on scroll -->

67

<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header mdl-layout--waterfall">

68

69

<!-- No drawer spacer -->

70

<div class="mdl-layout mdl-js-layout mdl-layout--no-drawer-button">

71

72

<!-- No desktop drawer -->

73

<div class="mdl-layout mdl-js-layout mdl-layout--no-desktop-drawer-button">

74

```

75

76

**Usage Examples:**

77

78

```javascript

79

// Access layout instance

80

const layout = document.querySelector('.mdl-js-layout').MaterialLayout;

81

82

// Toggle drawer programmatically

83

layout.toggleDrawer();

84

85

// Open drawer on button click

86

document.querySelector('#menu-button').addEventListener('click', () => {

87

layout.toggleDrawer();

88

});

89

90

// Close drawer when clicking on content

91

document.querySelector('.mdl-layout__content').addEventListener('click', () => {

92

const drawer = document.querySelector('.mdl-layout__drawer');

93

if (drawer.classList.contains('is-visible')) {

94

layout.toggleDrawer();

95

}

96

});

97

```

98

99

### Material Layout Tab

100

101

Individual tab component within a layout header tab bar.

102

103

```javascript { .api }

104

/**

105

* Material Design layout tab component

106

* CSS Class: mdl-js-layout (parent layout manages tabs)

107

* Widget: true (as MaterialLayoutTab)

108

*/

109

interface MaterialLayoutTab {

110

/** Programmatically select this tab and show associated panel */

111

show(): void;

112

}

113

```

114

115

**HTML Structure:**

116

117

```html

118

<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">

119

<header class="mdl-layout__header">

120

<div class="mdl-layout__header-row">

121

<span class="mdl-layout-title">Title</span>

122

</div>

123

<!-- Tabs -->

124

<div class="mdl-layout__tab-bar mdl-js-ripple-effect">

125

<a href="#scroll-tab-1" class="mdl-layout__tab is-active">Tab 1</a>

126

<a href="#scroll-tab-2" class="mdl-layout__tab">Tab 2</a>

127

<a href="#scroll-tab-3" class="mdl-layout__tab">Tab 3</a>

128

</div>

129

</header>

130

131

<main class="mdl-layout__content">

132

<section class="mdl-layout__tab-panel is-active" id="scroll-tab-1">

133

<div class="page-content"><!-- Your content goes here --></div>

134

</section>

135

<section class="mdl-layout__tab-panel" id="scroll-tab-2">

136

<div class="page-content"><!-- Your content goes here --></div>

137

</section>

138

<section class="mdl-layout__tab-panel" id="scroll-tab-3">

139

<div class="page-content"><!-- Your content goes here --></div>

140

</section>

141

</main>

142

</div>

143

```

144

145

**Usage Examples:**

146

147

```javascript

148

// Access tab instances

149

const tabs = document.querySelectorAll('.mdl-layout__tab');

150

const tabInstances = Array.from(tabs).map(tab => tab.MaterialLayoutTab);

151

152

// Programmatically switch to a specific tab

153

const secondTab = tabs[1].MaterialLayoutTab;

154

secondTab.show();

155

156

// Dynamic tab switching

157

function switchToTab(index) {

158

const tab = tabs[index];

159

if (tab && tab.MaterialLayoutTab) {

160

tab.MaterialLayoutTab.show();

161

}

162

}

163

164

// Listen for tab changes

165

document.addEventListener('click', (event) => {

166

if (event.target.matches('.mdl-layout__tab')) {

167

console.log('Tab clicked:', event.target.textContent);

168

}

169

});

170

```

171

172

### Material Tabs

173

174

Standalone tab component for organizing content into switchable sections.

175

176

```javascript { .api }

177

/**

178

* Material Design tabs component

179

* CSS Class: mdl-js-tabs

180

* Widget: false

181

*/

182

interface MaterialTabs {

183

// No public methods - behavior is entirely automatic

184

// Tabs are activated by clicking tab elements

185

}

186

```

187

188

**HTML Structure:**

189

190

```html

191

<!-- Standalone tabs -->

192

<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">

193

<div class="mdl-tabs__tab-bar">

194

<a href="#starks-panel" class="mdl-tabs__tab is-active">Starks</a>

195

<a href="#lannisters-panel" class="mdl-tabs__tab">Lannisters</a>

196

<a href="#targaryens-panel" class="mdl-tabs__tab">Targaryens</a>

197

</div>

198

199

<div class="mdl-tabs__panel is-active" id="starks-panel">

200

<ul>

201

<li>Eddard</li>

202

<li>Catelyn</li>

203

<li>Robb</li>

204

</ul>

205

</div>

206

<div class="mdl-tabs__panel" id="lannisters-panel">

207

<ul>

208

<li>Tywin</li>

209

<li>Cersei</li>

210

<li>Jaime</li>

211

</ul>

212

</div>

213

<div class="mdl-tabs__panel" id="targaryens-panel">

214

<ul>

215

<li>Viserys</li>

216

<li>Daenerys</li>

217

</ul>

218

</div>

219

</div>

220

```

221

222

**Usage Examples:**

223

224

```javascript

225

// Tabs work automatically, but you can listen for changes

226

document.addEventListener('click', (event) => {

227

if (event.target.matches('.mdl-tabs__tab')) {

228

const targetPanel = event.target.getAttribute('href');

229

console.log('Switching to panel:', targetPanel);

230

231

// Perform custom actions when tab changes

232

onTabChange(targetPanel);

233

}

234

});

235

236

function onTabChange(panelId) {

237

// Custom logic for tab changes

238

const panel = document.querySelector(panelId);

239

if (panel) {

240

// Load content dynamically if needed

241

loadPanelContent(panel);

242

}

243

}

244

245

// Programmatically activate a tab

246

function activateTab(tabSelector) {

247

const tab = document.querySelector(tabSelector);

248

const panel = document.querySelector(tab.getAttribute('href'));

249

250

// Remove active class from all tabs and panels

251

document.querySelectorAll('.mdl-tabs__tab').forEach(t => t.classList.remove('is-active'));

252

document.querySelectorAll('.mdl-tabs__panel').forEach(p => p.classList.remove('is-active'));

253

254

// Add active class to selected tab and panel

255

tab.classList.add('is-active');

256

panel.classList.add('is-active');

257

}

258

```

259

260

## Layout Constants

261

262

```javascript { .api }

263

/**

264

* Material Layout constants and configuration

265

*/

266

interface LayoutConstants {

267

/** Media query for maximum width */

268

MAX_WIDTH: '(max-width: 1024px)';

269

270

/** Pixels to scroll tabs when using arrow buttons */

271

TAB_SCROLL_PIXELS: 100;

272

273

/** Timeout for resize event handling */

274

RESIZE_TIMEOUT: 100;

275

276

/** Menu icon HTML entity */

277

MENU_ICON: '&#xE5D2;';

278

279

/** Left chevron icon name */

280

CHEVRON_LEFT: 'chevron_left';

281

282

/** Right chevron icon name */

283

CHEVRON_RIGHT: 'chevron_right';

284

}

285

286

/**

287

* Layout modes

288

*/

289

interface LayoutModes {

290

/** Standard layout mode */

291

STANDARD: 0;

292

293

/** Seamed layout mode */

294

SEAMED: 1;

295

296

/** Waterfall layout mode */

297

WATERFALL: 2;

298

299

/** Scroll layout mode */

300

SCROLL: 3;

301

}

302

303

/**

304

* Keyboard codes used by layout components

305

*/

306

interface LayoutKeyCodes {

307

ENTER: 13;

308

ESCAPE: 27;

309

SPACE: 32;

310

}

311

```

312

313

## Responsive Behavior

314

315

Layout components automatically adapt to different screen sizes:

316

317

```javascript

318

// Monitor responsive changes

319

const mediaQuery = window.matchMedia('(max-width: 1024px)');

320

321

mediaQuery.addListener((mq) => {

322

if (mq.matches) {

323

// Mobile/tablet view

324

console.log('Switched to mobile layout');

325

setupMobileNavigation();

326

} else {

327

// Desktop view

328

console.log('Switched to desktop layout');

329

setupDesktopNavigation();

330

}

331

});

332

333

function setupMobileNavigation() {

334

// Show drawer button

335

// Hide large-screen-only navigation

336

}

337

338

function setupDesktopNavigation() {

339

// Hide drawer button (if no-desktop-drawer-button class is used)

340

// Show large-screen navigation

341

}

342

```

343

344

## Layout Integration

345

346

```javascript

347

// Initialize layout with custom behavior

348

function initializeLayout() {

349

const layout = document.querySelector('.mdl-js-layout');

350

351

// Ensure layout is upgraded

352

componentHandler.upgradeElement(layout);

353

354

// Set up drawer close on content click

355

const content = layout.querySelector('.mdl-layout__content');

356

content.addEventListener('click', () => {

357

const drawer = layout.querySelector('.mdl-layout__drawer');

358

if (drawer.classList.contains('is-visible')) {

359

layout.MaterialLayout.toggleDrawer();

360

}

361

});

362

363

// Set up tab switching

364

const tabs = layout.querySelectorAll('.mdl-layout__tab');

365

tabs.forEach((tab, index) => {

366

tab.addEventListener('click', () => {

367

console.log('Layout tab clicked:', index);

368

// Custom tab switching logic

369

});

370

});

371

}

372

373

// Handle dynamic content updates

374

function updateLayoutContent(newContent) {

375

const contentArea = document.querySelector('.mdl-layout__content .page-content');

376

contentArea.innerHTML = newContent;

377

378

// Upgrade any new MDL components in the content

379

componentHandler.upgradeElements(contentArea.querySelectorAll('[class*="mdl-js-"]'));

380

}

381

```

382

383

## Accessibility

384

385

Layout components include accessibility features:

386

387

```javascript

388

// Keyboard navigation support

389

document.addEventListener('keydown', (event) => {

390

const layout = document.querySelector('.mdl-js-layout').MaterialLayout;

391

392

switch (event.key) {

393

case 'Escape':

394

// Close drawer on escape

395

const drawer = document.querySelector('.mdl-layout__drawer');

396

if (drawer.classList.contains('is-visible')) {

397

layout.toggleDrawer();

398

}

399

break;

400

401

case 'Tab':

402

// Handle tab navigation within drawer

403

if (event.target.closest('.mdl-layout__drawer')) {

404

handleDrawerTabNavigation(event);

405

}

406

break;

407

}

408

});

409

410

function handleDrawerTabNavigation(event) {

411

const drawer = document.querySelector('.mdl-layout__drawer');

412

const focusableElements = drawer.querySelectorAll('a, button, [tabindex]:not([tabindex="-1"])');

413

const firstElement = focusableElements[0];

414

const lastElement = focusableElements[focusableElements.length - 1];

415

416

if (event.shiftKey && event.target === firstElement) {

417

// Wrap to last element

418

event.preventDefault();

419

lastElement.focus();

420

} else if (!event.shiftKey && event.target === lastElement) {

421

// Wrap to first element

422

event.preventDefault();

423

firstElement.focus();

424

}

425

}

426

```