0
# Other Language Services
1
2
JSON schema validation, CSS/SCSS/Less support, and HTML/Handlebars language features in Monaco Editor.
3
4
## JSON Language Service
5
6
Monaco provides comprehensive JSON support with schema validation and IntelliSense.
7
8
### Core Import
9
10
```typescript
11
import * as monaco from 'monaco-editor';
12
13
// Access JSON defaults
14
const jsonDefaults = monaco.languages.json.jsonDefaults;
15
```
16
17
### JSON Configuration
18
19
```typescript { .api }
20
monaco.languages.json.jsonDefaults: LanguageServiceDefaults
21
```
22
23
Configuration object for JSON language service.
24
25
### Diagnostics Options
26
27
```typescript { .api }
28
jsonDefaults.setDiagnosticsOptions(options: DiagnosticsOptions): void
29
```
30
31
Configures JSON validation and diagnostics.
32
33
```typescript { .api }
34
interface DiagnosticsOptions {
35
validate?: boolean;
36
allowComments?: boolean;
37
schemas?: JSONSchema[];
38
enableSchemaRequest?: boolean;
39
hoverSettings?: HoverSettings;
40
completionSettings?: CompletionSettings;
41
}
42
```
43
44
```typescript
45
// Configure JSON validation
46
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
47
validate: true,
48
allowComments: false,
49
schemas: [
50
{
51
uri: 'http://json-schema.org/draft-07/schema#',
52
fileMatch: ['*'],
53
schema: {
54
type: 'object',
55
properties: {
56
name: { type: 'string' },
57
version: { type: 'string' },
58
dependencies: {
59
type: 'object',
60
additionalProperties: { type: 'string' }
61
}
62
}
63
}
64
}
65
],
66
enableSchemaRequest: true
67
});
68
```
69
70
### JSON Schema Support
71
72
```typescript { .api }
73
interface JSONSchema {
74
uri: string;
75
fileMatch?: string[];
76
schema?: any;
77
}
78
```
79
80
```typescript
81
// Package.json schema example
82
const packageJsonSchema = {
83
uri: 'http://json.schemastore.org/package',
84
fileMatch: ['package.json'],
85
schema: {
86
type: 'object',
87
properties: {
88
name: {
89
type: 'string',
90
description: 'The name of the package'
91
},
92
version: {
93
type: 'string',
94
pattern: '^\\d+\\.\\d+\\.\\d+',
95
description: 'Version must be a valid semver string'
96
},
97
main: {
98
type: 'string',
99
description: 'The main entry point'
100
},
101
scripts: {
102
type: 'object',
103
additionalProperties: {
104
type: 'string'
105
},
106
description: 'Script commands'
107
},
108
dependencies: {
109
type: 'object',
110
additionalProperties: {
111
type: 'string'
112
},
113
description: 'Package dependencies'
114
},
115
devDependencies: {
116
type: 'object',
117
additionalProperties: {
118
type: 'string'
119
},
120
description: 'Development dependencies'
121
}
122
},
123
required: ['name', 'version']
124
}
125
};
126
127
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
128
validate: true,
129
schemas: [packageJsonSchema]
130
});
131
```
132
133
### JSON Model Creation
134
135
```typescript
136
// Create a JSON model with schema validation
137
const packageJsonModel = monaco.editor.createModel(`{
138
"name": "my-project",
139
"version": "1.0.0",
140
"main": "index.js",
141
"scripts": {
142
"start": "node index.js",
143
"test": "jest"
144
},
145
"dependencies": {
146
"express": "^4.18.0"
147
},
148
"devDependencies": {
149
"jest": "^28.0.0"
150
}
151
}`, 'json', monaco.Uri.parse('file:///package.json'));
152
```
153
154
## CSS Language Service
155
156
Monaco supports CSS, SCSS, and Less with IntelliSense and validation.
157
158
### Core Import
159
160
```typescript
161
// Access CSS defaults
162
const cssDefaults = monaco.languages.css.cssDefaults;
163
const scssDefaults = monaco.languages.css.scssDefaults;
164
const lessDefaults = monaco.languages.css.lessDefaults;
165
```
166
167
### CSS Configuration
168
169
```typescript { .api }
170
cssDefaults.setOptions(options: LanguageServiceOptions): void
171
```
172
173
Configures CSS language service options.
174
175
```typescript { .api }
176
interface LanguageServiceOptions {
177
validate?: boolean;
178
lint?: LintSettings;
179
data?: CSSDataConfiguration;
180
hoverSettings?: HoverSettings;
181
completionSettings?: CompletionSettings;
182
}
183
```
184
185
```typescript
186
// Configure CSS options
187
monaco.languages.css.cssDefaults.setOptions({
188
validate: true,
189
lint: {
190
compatibleVendorPrefixes: 'ignore',
191
vendorPrefix: 'warning',
192
duplicateProperties: 'warning',
193
emptyRules: 'warning',
194
importStatemements: 'ignore',
195
boxModel: 'ignore',
196
universalSelector: 'ignore',
197
zeroUnits: 'ignore',
198
fontFaceProperties: 'warning',
199
hexColorLength: 'error',
200
argumentsInColorFunction: 'error',
201
unknownProperties: 'warning',
202
ieHack: 'ignore',
203
unknownVendorSpecificProperties: 'ignore',
204
propertyIgnoredDueToDisplay: 'warning',
205
important: 'ignore',
206
float: 'ignore',
207
idSelector: 'ignore'
208
}
209
});
210
211
// Configure SCSS options
212
monaco.languages.css.scssDefaults.setOptions({
213
validate: true,
214
lint: {
215
// SCSS-specific lint rules
216
unknownAtRules: 'ignore' // Allow SCSS @rules
217
}
218
});
219
220
// Configure Less options
221
monaco.languages.css.lessDefaults.setOptions({
222
validate: true,
223
lint: {
224
// Less-specific lint rules
225
unknownAtRules: 'ignore' // Allow Less @rules
226
}
227
});
228
```
229
230
### CSS Custom Data
231
232
```typescript { .api }
233
interface CSSDataConfiguration {
234
version: 1;
235
properties?: IPropertyData[];
236
atDirectives?: IAtDirectiveData[];
237
pseudoClasses?: IPseudoClassData[];
238
pseudoElements?: IPseudoElementData[];
239
}
240
```
241
242
```typescript
243
// Add custom CSS properties
244
const customCSSData = {
245
version: 1,
246
properties: [
247
{
248
name: '--primary-color',
249
description: 'Primary theme color',
250
browsers: ['FF', 'S', 'C', 'IE', 'E', 'O']
251
},
252
{
253
name: '--secondary-color',
254
description: 'Secondary theme color',
255
browsers: ['FF', 'S', 'C', 'IE', 'E', 'O']
256
}
257
],
258
atDirectives: [
259
{
260
name: '@custom-media',
261
description: 'Define custom media queries',
262
browsers: ['FF', 'S', 'C']
263
}
264
]
265
};
266
267
monaco.languages.css.cssDefaults.setOptions({
268
data: customCSSData
269
});
270
```
271
272
### CSS Model Examples
273
274
```typescript
275
// CSS model
276
const cssModel = monaco.editor.createModel(`
277
:root {
278
--primary-color: #3498db;
279
--secondary-color: #2ecc71;
280
--font-size: 16px;
281
}
282
283
.container {
284
max-width: 1200px;
285
margin: 0 auto;
286
padding: 20px;
287
font-size: var(--font-size);
288
}
289
290
.button {
291
background-color: var(--primary-color);
292
color: white;
293
border: none;
294
padding: 10px 20px;
295
border-radius: 4px;
296
cursor: pointer;
297
transition: background-color 0.3s ease;
298
}
299
300
.button:hover {
301
background-color: var(--secondary-color);
302
}
303
304
@media (max-width: 768px) {
305
.container {
306
padding: 10px;
307
}
308
}
309
`, 'css', monaco.Uri.parse('file:///styles.css'));
310
311
// SCSS model
312
const scssModel = monaco.editor.createModel(`
313
$primary-color: #3498db;
314
$secondary-color: #2ecc71;
315
$border-radius: 4px;
316
317
%button-base {
318
border: none;
319
padding: 10px 20px;
320
border-radius: $border-radius;
321
cursor: pointer;
322
transition: background-color 0.3s ease;
323
}
324
325
.button {
326
@extend %button-base;
327
background-color: $primary-color;
328
color: white;
329
330
&:hover {
331
background-color: darken($primary-color, 10%);
332
}
333
334
&.secondary {
335
background-color: $secondary-color;
336
337
&:hover {
338
background-color: darken($secondary-color, 10%);
339
}
340
}
341
}
342
343
@mixin respond-to($breakpoint) {
344
@if $breakpoint == mobile {
345
@media (max-width: 768px) { @content; }
346
}
347
@if $breakpoint == tablet {
348
@media (min-width: 769px) and (max-width: 1024px) { @content; }
349
}
350
}
351
352
.container {
353
max-width: 1200px;
354
margin: 0 auto;
355
padding: 20px;
356
357
@include respond-to(mobile) {
358
padding: 10px;
359
}
360
}
361
`, 'scss', monaco.Uri.parse('file:///styles.scss'));
362
363
// Less model
364
const lessModel = monaco.editor.createModel(`
365
@primary-color: #3498db;
366
@secondary-color: #2ecc71;
367
@border-radius: 4px;
368
369
.button-mixin(@bg-color) {
370
background-color: @bg-color;
371
border: none;
372
padding: 10px 20px;
373
border-radius: @border-radius;
374
cursor: pointer;
375
transition: background-color 0.3s ease;
376
377
&:hover {
378
background-color: darken(@bg-color, 10%);
379
}
380
}
381
382
.button {
383
.button-mixin(@primary-color);
384
color: white;
385
386
&.secondary {
387
.button-mixin(@secondary-color);
388
}
389
}
390
391
.container {
392
max-width: 1200px;
393
margin: 0 auto;
394
padding: 20px;
395
396
@media (max-width: 768px) {
397
padding: 10px;
398
}
399
}
400
`, 'less', monaco.Uri.parse('file:///styles.less'));
401
```
402
403
## HTML Language Service
404
405
Monaco provides HTML support with tag completion, attribute validation, and embedded CSS/JavaScript.
406
407
### Core Import
408
409
```typescript
410
// Access HTML defaults
411
const htmlDefaults = monaco.languages.html.htmlDefaults;
412
const handlebarsDefaults = monaco.languages.html.handlebarDefaults;
413
const razorDefaults = monaco.languages.html.razorDefaults;
414
```
415
416
### HTML Configuration
417
418
```typescript { .api }
419
htmlDefaults.setOptions(options: HTMLLanguageServiceOptions): void
420
```
421
422
Configures HTML language service options.
423
424
```typescript { .api }
425
interface HTMLLanguageServiceOptions {
426
format?: HTMLFormatConfiguration;
427
suggest?: HTMLSuggestOptions;
428
data?: HTMLDataConfiguration;
429
}
430
```
431
432
```typescript
433
// Configure HTML options
434
monaco.languages.html.htmlDefaults.setOptions({
435
format: {
436
tabSize: 2,
437
insertSpaces: true,
438
wrapLineLength: 120,
439
unformatted: 'default',
440
contentUnformatted: 'pre,code,textarea',
441
indentInnerHtml: false,
442
preserveNewLines: true,
443
maxPreserveNewLines: 2,
444
indentHandlebars: false,
445
endWithNewline: false,
446
extraLiners: 'head, body, /html'
447
},
448
suggest: {
449
html5: true,
450
angular1: false,
451
ionic: false
452
}
453
});
454
```
455
456
### HTML Custom Data
457
458
```typescript { .api }
459
interface HTMLDataConfiguration {
460
version: 1;
461
tags?: ITagData[];
462
attributes?: IAttributeData[];
463
valueSets?: IValueSet[];
464
}
465
```
466
467
```typescript
468
// Add custom HTML elements and attributes
469
const customHTMLData = {
470
version: 1,
471
tags: [
472
{
473
name: 'my-component',
474
description: 'Custom component',
475
attributes: [
476
{
477
name: 'prop1',
478
description: 'First property',
479
valueSet: 'string'
480
},
481
{
482
name: 'prop2',
483
description: 'Second property',
484
valueSet: 'boolean'
485
}
486
]
487
}
488
],
489
attributes: [
490
{
491
name: 'data-testid',
492
description: 'Test identifier for automated testing',
493
valueSet: 'string'
494
}
495
]
496
};
497
498
monaco.languages.html.htmlDefaults.setOptions({
499
data: customHTMLData
500
});
501
```
502
503
### HTML Model Examples
504
505
```typescript
506
// HTML model
507
const htmlModel = monaco.editor.createModel(`
508
<!DOCTYPE html>
509
<html lang="en">
510
<head>
511
<meta charset="UTF-8">
512
<meta name="viewport" content="width=device-width, initial-scale=1.0">
513
<title>Monaco Editor Example</title>
514
<style>
515
body {
516
font-family: Arial, sans-serif;
517
margin: 0;
518
padding: 20px;
519
}
520
.container {
521
max-width: 800px;
522
margin: 0 auto;
523
}
524
</style>
525
</head>
526
<body>
527
<div class="container">
528
<h1>Welcome to Monaco Editor</h1>
529
<p>This is a demonstration of HTML editing capabilities.</p>
530
<my-component prop1="value1" prop2="true" data-testid="demo-component">
531
<span>Custom component content</span>
532
</my-component>
533
<button onclick="handleClick()">Click me</button>
534
</div>
535
536
<script>
537
function handleClick() {
538
alert('Button clicked!');
539
}
540
</script>
541
</body>
542
</html>
543
`, 'html', monaco.Uri.parse('file:///index.html'));
544
545
// Handlebars model
546
const handlebarsModel = monaco.editor.createModel(`
547
<!DOCTYPE html>
548
<html>
549
<head>
550
<title>{{title}}</title>
551
</head>
552
<body>
553
<h1>{{heading}}</h1>
554
555
{{#if user}}
556
<p>Welcome, {{user.name}}!</p>
557
<p>Email: {{user.email}}</p>
558
{{else}}
559
<p>Please log in.</p>
560
{{/if}}
561
562
<ul>
563
{{#each items}}
564
<li>
565
<strong>{{this.name}}</strong>
566
{{#if this.description}}
567
- {{this.description}}
568
{{/if}}
569
</li>
570
{{/each}}
571
</ul>
572
573
{{> footer}}
574
</body>
575
</html>
576
`, 'handlebars', monaco.Uri.parse('file:///template.hbs'));
577
```
578
579
## Language Service Features
580
581
All language services provide common IntelliSense features:
582
583
### Code Completion
584
- Tag and attribute completion for HTML
585
- Property and value completion for CSS
586
- Schema-based completion for JSON
587
588
### Validation
589
- Syntax error detection
590
- Schema validation for JSON
591
- CSS property validation
592
- HTML tag and attribute validation
593
594
### Hover Information
595
- Property descriptions
596
- Value information
597
- Schema documentation
598
599
### Formatting
600
- Automatic indentation
601
- Code beautification
602
- Configurable formatting rules
603
604
### Color Support
605
- Color decorations in CSS
606
- Color picker integration
607
- Color format conversion
608
609
## Worker Configuration
610
611
Language services run in web workers for performance:
612
613
```typescript
614
self.MonacoEnvironment = {
615
getWorkerUrl: function (moduleId, label) {
616
if (label === 'json') {
617
return './json.worker.bundle.js';
618
}
619
if (label === 'css' || label === 'scss' || label === 'less') {
620
return './css.worker.bundle.js';
621
}
622
if (label === 'html' || label === 'handlebars' || label === 'razor') {
623
return './html.worker.bundle.js';
624
}
625
return './editor.worker.bundle.js';
626
}
627
};
628
```
629
630
## Complete Example
631
632
```typescript
633
// Configure all language services
634
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
635
validate: true,
636
allowComments: true,
637
schemas: [
638
{
639
uri: 'http://json-schema.org/package',
640
fileMatch: ['package.json'],
641
schema: packageJsonSchema
642
}
643
]
644
});
645
646
monaco.languages.css.cssDefaults.setOptions({
647
validate: true,
648
lint: {
649
duplicateProperties: 'warning',
650
unknownProperties: 'warning'
651
}
652
});
653
654
monaco.languages.html.htmlDefaults.setOptions({
655
format: {
656
tabSize: 2,
657
insertSpaces: true
658
},
659
suggest: {
660
html5: true
661
}
662
});
663
664
// Create models for different languages
665
const models = [
666
monaco.editor.createModel(jsonContent, 'json', monaco.Uri.parse('file:///config.json')),
667
monaco.editor.createModel(cssContent, 'css', monaco.Uri.parse('file:///styles.css')),
668
monaco.editor.createModel(htmlContent, 'html', monaco.Uri.parse('file:///index.html'))
669
];
670
671
// Create editor and switch between models
672
const editor = monaco.editor.create(document.getElementById('container'));
673
editor.setModel(models[0]); // Start with JSON
674
```