0
# Layout & Style System
1
2
The layout and style system provides CSS-based positioning, sizing, and appearance management for Jupyter widgets through trait-based property handling.
3
4
## Capabilities
5
6
### Layout System
7
8
CSS-based layout management with support for flexbox, grid, positioning, and spacing properties.
9
10
```typescript { .api }
11
/**
12
* Model for widget layout properties, supports comprehensive CSS layout
13
*/
14
class LayoutModel extends WidgetModel {
15
/**
16
* Default attributes including all supported CSS properties
17
*/
18
defaults(): Backbone.ObjectHash;
19
}
20
```
21
22
**Supported Layout Properties:**
23
24
All layout properties default to `null` and map directly to CSS properties:
25
26
**Position & Size:**
27
- `top`, `right`, `bottom`, `left` - Positioning values
28
- `width`, `height` - Element dimensions
29
- `min_width`, `min_height`, `max_width`, `max_height` - Size constraints
30
31
**Flexbox Layout:**
32
- `flex` - Flex grow/shrink/basis shorthand
33
- `flex_flow` - Flex direction and wrap shorthand
34
- `align_content` - Align flex lines
35
- `align_items` - Align flex items
36
- `align_self` - Individual item alignment
37
- `justify_content` - Main axis alignment
38
- `justify_items` - Grid item justification
39
- `order` - Flex/grid item order
40
41
**Spacing:**
42
- `margin` - Outer spacing
43
- `padding` - Inner spacing
44
45
**Border:**
46
- `border_top`, `border_right`, `border_bottom`, `border_left` - Individual borders
47
48
**Display:**
49
- `display` - Display type (block, flex, grid, etc.)
50
- `visibility` - Element visibility
51
- `overflow` - Content overflow behavior
52
53
**Grid Layout:**
54
- `grid_auto_columns`, `grid_auto_rows` - Implicit grid sizing
55
- `grid_auto_flow` - Grid item placement algorithm
56
- `grid_gap` - Grid spacing
57
- `grid_template_rows`, `grid_template_columns` - Explicit grid tracks
58
- `grid_template_areas` - Named grid areas
59
- `grid_row`, `grid_column` - Item grid placement
60
- `grid_area` - Item grid area assignment
61
62
**Image-specific:**
63
- `object_fit` - Image scaling behavior
64
- `object_position` - Image positioning
65
66
### Layout View
67
68
View component that applies layout properties to the parent widget element.
69
70
```typescript { .api }
71
/**
72
* View for applying layout styles to the parent widget element
73
*/
74
class LayoutView extends WidgetView {
75
/**
76
* Initialize layout view and register all CSS traits
77
* @param parameters - View initialization parameters
78
*/
79
initialize(parameters: WidgetView.IInitializeParameters): void;
80
81
/**
82
* Register a CSS trait for monitoring and application
83
* @param trait - CSS property name to register
84
*/
85
registerTrait(trait: string): void;
86
87
/**
88
* Convert trait name to CSS property name
89
* @param trait - Model trait name (with underscores)
90
* @returns CSS property name (with hyphens)
91
*/
92
css_name(trait: string): string;
93
94
/**
95
* Handle changes to layout traits and apply to parent element
96
* @param trait - Name of the changed trait
97
* @param value - New value for the trait
98
*/
99
handleChange(trait: string, value: any): void;
100
101
/**
102
* Remove all layout styles from the parent element
103
*/
104
unlayout(): void;
105
}
106
```
107
108
**Usage Examples:**
109
110
```typescript
111
// Create layout model with flexbox properties
112
const layoutModel = new LayoutModel({
113
display: 'flex',
114
flex_direction: 'column',
115
align_items: 'center',
116
padding: '10px',
117
margin: '5px',
118
width: '300px',
119
height: '200px'
120
});
121
122
// Apply to widget
123
widget.set('layout', layoutModel);
124
125
// Dynamic layout updates
126
layoutModel.set({
127
width: '400px',
128
justify_content: 'space-between'
129
});
130
131
// Grid layout example
132
const gridLayout = new LayoutModel({
133
display: 'grid',
134
grid_template_columns: '1fr 2fr 1fr',
135
grid_template_rows: 'auto 1fr auto',
136
grid_gap: '10px',
137
grid_template_areas: `
138
"header header header"
139
"sidebar main aside"
140
"footer footer footer"
141
`
142
});
143
```
144
145
### Style System
146
147
Flexible styling system with custom property definitions and selector-based application.
148
149
```typescript { .api }
150
/**
151
* Base model for widget styling with configurable style properties
152
*/
153
class StyleModel extends WidgetModel {
154
/**
155
* Default attributes based on defined style properties
156
*/
157
defaults(): Backbone.ObjectHash;
158
159
/**
160
* Static definition of available style properties
161
*/
162
static styleProperties: { [s: string]: IStyleProperty };
163
}
164
165
/**
166
* Configuration for individual style properties
167
*/
168
interface IStyleProperty {
169
/**
170
* CSS attribute name to apply
171
*/
172
attribute: string;
173
174
/**
175
* CSS selector for target elements (empty string for widget root)
176
*/
177
selector: string;
178
179
/**
180
* Default value for the property
181
*/
182
default: string;
183
}
184
```
185
186
### Style View
187
188
View component that applies custom styles to widget elements based on selectors.
189
190
```typescript { .api }
191
/**
192
* View for applying custom styles to widget elements
193
*/
194
class StyleView extends WidgetView {
195
/**
196
* Initialize style view and register all defined style traits
197
* @param parameters - View initialization parameters
198
*/
199
initialize(parameters: WidgetView.IInitializeParameters): void;
200
201
/**
202
* Register a style trait for monitoring
203
* @param trait - Style trait name to register
204
*/
205
registerTrait(trait: string): void;
206
207
/**
208
* Handle changes to style traits and apply to target elements
209
* @param trait - Name of the changed trait
210
* @param value - New value for the trait
211
*/
212
handleChange(trait: string, value: any): void;
213
214
/**
215
* Apply all registered styles to their target elements
216
*/
217
style(): void;
218
219
/**
220
* Remove all applied styles from target elements
221
*/
222
unstyle(): void;
223
}
224
```
225
226
**Usage Examples:**
227
228
```typescript
229
// Define custom style properties
230
class ButtonStyleModel extends StyleModel {
231
static styleProperties = {
232
button_color: {
233
attribute: 'background-color',
234
selector: 'button',
235
default: '#ffffff'
236
},
237
text_color: {
238
attribute: 'color',
239
selector: 'button',
240
default: '#000000'
241
},
242
border_radius: {
243
attribute: 'border-radius',
244
selector: 'button',
245
default: '4px'
246
},
247
font_weight: {
248
attribute: 'font-weight',
249
selector: '', // Apply to root element
250
default: 'normal'
251
}
252
};
253
}
254
255
// Create and apply styles
256
const buttonStyle = new ButtonStyleModel({
257
button_color: '#007bff',
258
text_color: '#ffffff',
259
border_radius: '8px',
260
font_weight: 'bold'
261
});
262
263
widget.set('style', buttonStyle);
264
265
// Dynamic style updates
266
buttonStyle.set('button_color', '#28a745'); // Changes button background
267
```
268
269
## Advanced Layout Patterns
270
271
### Responsive Layout
272
273
```typescript
274
// Create responsive layout that adapts to container size
275
const responsiveLayout = new LayoutModel({
276
display: 'grid',
277
grid_template_columns: 'repeat(auto-fit, minmax(250px, 1fr))',
278
grid_gap: '1rem',
279
padding: '1rem'
280
});
281
282
// Media query-like behavior through dynamic updates
283
const updateLayoutForSize = (containerWidth: number) => {
284
if (containerWidth < 600) {
285
responsiveLayout.set({
286
grid_template_columns: '1fr',
287
padding: '0.5rem'
288
});
289
} else if (containerWidth < 900) {
290
responsiveLayout.set({
291
grid_template_columns: 'repeat(2, 1fr)',
292
padding: '0.75rem'
293
});
294
} else {
295
responsiveLayout.set({
296
grid_template_columns: 'repeat(3, 1fr)',
297
padding: '1rem'
298
});
299
}
300
};
301
```
302
303
### Complex Grid Layouts
304
305
```typescript
306
// Dashboard-style grid layout
307
const dashboardLayout = new LayoutModel({
308
display: 'grid',
309
grid_template_columns: '200px 1fr 250px',
310
grid_template_rows: '60px 1fr 40px',
311
grid_template_areas: `
312
"nav header tools"
313
"nav main sidebar"
314
"nav footer sidebar"
315
`,
316
height: '100vh',
317
grid_gap: '8px'
318
});
319
320
// Individual widget positioning
321
const headerWidget = new LayoutModel({
322
grid_area: 'header',
323
display: 'flex',
324
align_items: 'center',
325
padding: '0 20px'
326
});
327
328
const mainWidget = new LayoutModel({
329
grid_area: 'main',
330
overflow: 'auto',
331
padding: '20px'
332
});
333
```
334
335
### Flexbox Patterns
336
337
```typescript
338
// Centered content layout
339
const centeredLayout = new LayoutModel({
340
display: 'flex',
341
align_items: 'center',
342
justify_content: 'center',
343
min_height: '300px'
344
});
345
346
// Toolbar layout
347
const toolbarLayout = new LayoutModel({
348
display: 'flex',
349
align_items: 'center',
350
justify_content: 'space-between',
351
padding: '8px 16px',
352
border_bottom: '1px solid #ccc'
353
});
354
355
// Card layout with flex content
356
const cardLayout = new LayoutModel({
357
display: 'flex',
358
flex_direction: 'column',
359
border: '1px solid #ddd',
360
border_radius: '8px',
361
overflow: 'hidden',
362
max_width: '350px'
363
});
364
```
365
366
## Style Property Patterns
367
368
### Theme-based Styling
369
370
```typescript
371
// Define theme-aware style model
372
class ThemedStyleModel extends StyleModel {
373
static styleProperties = {
374
primary_color: {
375
attribute: '--primary-color',
376
selector: '',
377
default: '#007bff'
378
},
379
secondary_color: {
380
attribute: '--secondary-color',
381
selector: '',
382
default: '#6c757d'
383
},
384
background_color: {
385
attribute: 'background-color',
386
selector: '',
387
default: '#ffffff'
388
},
389
text_color: {
390
attribute: 'color',
391
selector: '',
392
default: '#333333'
393
}
394
};
395
}
396
397
// Apply theme
398
const lightTheme = new ThemedStyleModel({
399
primary_color: '#007bff',
400
background_color: '#ffffff',
401
text_color: '#333333'
402
});
403
404
const darkTheme = new ThemedStyleModel({
405
primary_color: '#0d6efd',
406
background_color: '#1a1a1a',
407
text_color: '#ffffff'
408
});
409
```
410
411
### Component-specific Styling
412
413
```typescript
414
// Multi-element styling
415
class FormStyleModel extends StyleModel {
416
static styleProperties = {
417
label_color: {
418
attribute: 'color',
419
selector: 'label',
420
default: '#495057'
421
},
422
input_border: {
423
attribute: 'border',
424
selector: 'input, select, textarea',
425
default: '1px solid #ced4da'
426
},
427
input_focus_color: {
428
attribute: 'border-color',
429
selector: 'input:focus, select:focus, textarea:focus',
430
default: '#007bff'
431
},
432
error_color: {
433
attribute: 'color',
434
selector: '.error-message',
435
default: '#dc3545'
436
}
437
};
438
}
439
```
440
441
## Layout and Style Integration
442
443
```typescript
444
// Combine layout and style for complete widget theming
445
class ThemedWidget extends DOMWidgetModel {
446
defaults() {
447
return {
448
...super.defaults(),
449
layout: new LayoutModel({
450
padding: '16px',
451
border_radius: '8px',
452
box_shadow: '0 2px 4px rgba(0,0,0,0.1)'
453
}),
454
style: new ThemedStyleModel({
455
background_color: '#f8f9fa',
456
text_color: '#495057'
457
})
458
};
459
}
460
}
461
462
// Apply coordinated layout and styling
463
const createStyledWidget = (theme: 'light' | 'dark') => {
464
const layout = new LayoutModel({
465
padding: '20px',
466
border_radius: '12px',
467
box_shadow: theme === 'light'
468
? '0 4px 6px rgba(0,0,0,0.1)'
469
: '0 4px 6px rgba(0,0,0,0.3)'
470
});
471
472
const style = new ThemedStyleModel(
473
theme === 'light'
474
? { background_color: '#ffffff', text_color: '#333333' }
475
: { background_color: '#2d3748', text_color: '#ffffff' }
476
);
477
478
return { layout, style };
479
};
480
```