rt-native 1.0.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +866 -0
  3. package/package.json +52 -0
  4. package/rt-native.js +6809 -0
package/README.md ADDED
@@ -0,0 +1,866 @@
1
+ # `<rt-native>` — Native Web Component Rich Text Editor
2
+
3
+ `rt-native.js` HTML Editor is a free native web component that provides accessibility features and a wide variety of elements and customizations that make it one of the most robust and flexible HTML editors available. It allows the programmer to apply custom .css files to the preview window, so see how the content will be displayed in production. The editor uses embedded .svg Google Font Icons and the shadow DOM to isolate the HTML from inheriting the existing page styles. No frameworks, no build step, no dependencies — drop **one script tag** into any HTML page and you're done.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Files](#files)
10
+ 2. [Quick Start](#quick-start)
11
+ 3. [HTML Attributes](#html-attributes)
12
+ 4. [JavaScript API](#javascript-api)
13
+ - [getValue()](#getvalue)
14
+ - [getPlainText()](#getplaintext)
15
+ - [setValue()](#setvalue)
16
+ - [configure()](#configure)
17
+ - [setReadOnly()](#setreadonly)
18
+ - [setPreviewCssFiles()](#setpreviewcssfiles)
19
+ - [setPreviewCssFile()](#setpreviewcssfile)
20
+ - [setPreviewCss()](#setpreviewcss)
21
+ 5. [Events](#events)
22
+ 6. [CSS Variables](#css-variables)
23
+ - [Toolbar](#toolbar-variables)
24
+ - [Buttons](#button-variables)
25
+ - [Content Area](#content-area-variables)
26
+ - [Editor Container](#editor-container-variables)
27
+ - [Scrollbars](#scrollbar-variables)
28
+ - [Blockquote](#blockquote-variables)
29
+ - [Code / Pre](#code--pre-variables)
30
+ - [Modals & Dialogs](#modal--dialog-variables)
31
+ 7. [Theming with CSS Classes](#theming-with-css-classes)
32
+ 8. [configure() Reference](#configure-reference)
33
+ - [toolbar](#toolbar-options)
34
+ - [button](#button-options)
35
+ - [content](#content-options)
36
+ - [editor](#editor-options)
37
+ - [scroll](#scroll-options)
38
+ - [modal](#modal-options)
39
+ - [quote](#quote-options)
40
+ - [code](#code-options)
41
+ - [visibility](#visibility-options)
42
+ 9. [Preview Window Styling](#preview-window-styling)
43
+ 10. [Toolbar Buttons](#toolbar-buttons)
44
+ 11. [Keyboard Shortcuts](#keyboard-shortcuts)
45
+ 12. [Accessibility](#accessibility)
46
+ 13. [Multiple Instances](#multiple-instances)
47
+ 14. [Browser Support](#browser-support)
48
+
49
+ ---
50
+
51
+ ## Files
52
+
53
+ | File | Purpose |
54
+ |---|---|
55
+ | `rt-native.js` | **The only required file.** Contains the complete editor engine, web component wrapper, all CSS defaults, and all dialog styles — everything is self-contained. |
56
+ | `preview1.css` | Optional. Example preview stylesheet — base text, headings, links, blockquotes, and code/pre styles. Load with `setPreviewCssFiles()`. |
57
+ | `preview2.css` | Optional. Example preview stylesheet — tables, lists, images, and horizontal rules. Load with `setPreviewCssFiles()`. |
58
+
59
+ ---
60
+
61
+ ## Quick Start
62
+
63
+ ```html
64
+ <!DOCTYPE html>
65
+ <html lang="en">
66
+ <head>
67
+ <meta charset="UTF-8">
68
+ </head>
69
+ <body>
70
+
71
+ <rt-native id="editor" height="400px"></rt-native>
72
+
73
+ <script src="rt-native.js"></script>
74
+ <script>
75
+ const editor = document.getElementById('editor');
76
+
77
+ // Read the content
78
+ console.log(editor.getValue());
79
+
80
+ // Write content
81
+ editor.setValue('<p>Hello <strong>world</strong></p>');
82
+
83
+ // React to changes
84
+ editor.addEventListener('change', e => {
85
+ console.log(e.detail.value);
86
+ });
87
+ </script>
88
+ </body>
89
+ </html>
90
+ ```
91
+
92
+ ---
93
+
94
+ ## HTML Attributes
95
+
96
+ | Attribute | Type | Default | Description |
97
+ |---|---|---|---|
98
+ | `value` | `string` | `''` | Initial HTML content of the editor. |
99
+ | `width` | `string` | `100%` | Editor width. Any valid CSS value (`px`, `%`, `vw`, etc.). |
100
+ | `height` | `string` | `300px` | Editor height. Any valid CSS value. |
101
+ | `placeholder` | `string` | — | Placeholder text shown when the editor is empty. |
102
+ | `readonly` | boolean (presence) | — | Puts the editor in read-only mode. Hides the toolbar. |
103
+ | `aria-label` | `string` | `'Rich text editor'` | Accessible name for the editor region. |
104
+ | `label` | `string` | — | Alternative to `aria-label` for the accessible name. |
105
+ | `config` | JSON string | — | Declarative configuration. Parsed and passed to `configure()` on connect. |
106
+
107
+ ### Example
108
+
109
+ ```html
110
+ <!-- Inline value and placeholder -->
111
+ <rt-native value="<p>Hello</p>" width="800px" height="500px"
112
+ placeholder="Start typing…"></rt-native>
113
+
114
+ <!-- Read-only display -->
115
+ <rt-native readonly value="<p>This content cannot be edited.</p>"></rt-native>
116
+
117
+ <!-- Accessible label -->
118
+ <rt-native aria-label="Article body"></rt-native>
119
+
120
+ <!-- Declarative config (JSON attribute) -->
121
+ <rt-native config='{"editor":{"height":"500px"},"visibility":{"embedMedia":false}}'></rt-native>
122
+ ```
123
+
124
+ > **Note:** `width` and `height` are shorthand for `--rtb-editor-width` and `--rtb-editor-height`. They can also be set via CSS variables or `configure({ editor: { width, height } })`.
125
+
126
+ ---
127
+
128
+ ## JavaScript API
129
+
130
+ ### getValue()
131
+
132
+ Returns the current editor content as an **HTML string**.
133
+
134
+ ```js
135
+ const html = editor.getValue();
136
+ // "<p>Hello <strong>world</strong></p>"
137
+ ```
138
+
139
+ ### getPlainText()
140
+
141
+ Returns the editor content as **plain text** (all HTML tags stripped).
142
+
143
+ ```js
144
+ const text = editor.getPlainText();
145
+ // "Hello world"
146
+ ```
147
+
148
+ ### setValue()
149
+
150
+ Replaces the editor content with the supplied HTML string. Passing an empty string or `null` clears the editor.
151
+
152
+ ```js
153
+ editor.setValue('<h2>New content</h2><p>Paragraph text.</p>');
154
+ editor.setValue(''); // clear
155
+ ```
156
+
157
+ ### configure()
158
+
159
+ Applies appearance and behaviour options. Can be called at any time — style changes take effect immediately via CSS custom properties; visibility changes trigger a minimal toolbar re-render.
160
+
161
+ ```js
162
+ editor.configure({
163
+ toolbar: { /* ... */ },
164
+ button: { /* ... */ },
165
+ content: { /* ... */ },
166
+ editor: { /* ... */ },
167
+ scroll: { /* ... */ },
168
+ modal: { /* ... */ },
169
+ visibility: { /* ... */ },
170
+ });
171
+ ```
172
+
173
+ See [configure() Reference](#configure-reference) for the full option list.
174
+
175
+ ### setReadOnly()
176
+
177
+ Programmatically enable or disable read-only mode. When read-only, the toolbar is hidden and the content area cannot be edited.
178
+
179
+ ```js
180
+ editor.setReadOnly(true); // lock
181
+ editor.setReadOnly(false); // unlock
182
+ ```
183
+
184
+ The `readOnly` getter reflects the current state:
185
+
186
+ ```js
187
+ if (editor.readOnly) {
188
+ console.log('Editor is locked.');
189
+ }
190
+ ```
191
+
192
+ Read-only mode can also be set declaratively via the `readonly` HTML attribute:
193
+
194
+ ```html
195
+ <rt-native readonly></rt-native>
196
+ ```
197
+
198
+ ### setPreviewCssFiles()
199
+
200
+ Sets one or more CSS files to apply to **both the editor content area and the preview window**. Rules are automatically scoped so they only style the HTML being edited — the toolbar, menus, and dialogs are never affected. Call with no arguments to remove all files.
201
+
202
+ ```js
203
+ // Load two stylesheets
204
+ editor.setPreviewCssFiles('preview1.css', 'preview2.css');
205
+
206
+ // Load a single file
207
+ editor.setPreviewCssFiles('/styles/my-content.css');
208
+
209
+ // Clear all preview files
210
+ editor.setPreviewCssFiles();
211
+ ```
212
+
213
+ > **CORS:** Files are loaded with `fetch()`. They must be served from the same origin or include appropriate `Access-Control-Allow-Origin` headers.
214
+
215
+ ### setPreviewCssFile()
216
+
217
+ Convenience method that sets a **single** CSS file. Equivalent to `setPreviewCssFiles(url)`.
218
+
219
+ ```js
220
+ editor.setPreviewCssFile('/styles/content.css');
221
+
222
+ // Clear
223
+ editor.setPreviewCssFile('');
224
+ ```
225
+
226
+ ### setPreviewCss()
227
+
228
+ Supplies **inline CSS** to apply to both the editor content area and the preview window. Rules are automatically scoped, exactly like `setPreviewCssFiles()`. Call with no argument (or `''`) to clear.
229
+
230
+ ```js
231
+ editor.setPreviewCss(`
232
+ h1, h2, h3 { color: #0a2540; }
233
+ blockquote {
234
+ border-left-color: #635bff;
235
+ background: #f8f6ff;
236
+ }
237
+ `);
238
+
239
+ // Clear
240
+ editor.setPreviewCss('');
241
+ ```
242
+
243
+ `setPreviewCss()` and `setPreviewCssFiles()` are independent — both can be active at the same time. File rules are applied first; inline rules are appended after, so inline CSS always wins when there is a conflict.
244
+
245
+ ---
246
+
247
+ ## Events
248
+
249
+ ### `change`
250
+
251
+ Fired on the element whenever the editor content changes. The event **bubbles** and is **composed** (crosses shadow DOM boundaries).
252
+
253
+ ```js
254
+ editor.addEventListener('change', (event) => {
255
+ const html = event.detail.value; // current HTML string
256
+ console.log(html);
257
+ });
258
+ ```
259
+
260
+ | Property | Value |
261
+ |---|---|
262
+ | `event.detail.value` | Current editor HTML as a string |
263
+ | `event.bubbles` | `true` |
264
+ | `event.composed` | `true` |
265
+
266
+ ---
267
+
268
+ ## CSS Variables
269
+
270
+ All visual aspects of the editor are controlled through CSS custom properties declared on the `rt-native` element. Default values are injected automatically by `rt-native.js` when the first editor mounts — no stylesheet required. Override any variable in your own CSS to theme the editor.
271
+
272
+ ```css
273
+ /* Override globally (all editors on the page) */
274
+ rt-native {
275
+ --rtb-toolbar-bg: #f5f5f5;
276
+ --rtb-btn-size: 14px;
277
+ }
278
+
279
+ /* Override for a specific editor */
280
+ #my-editor {
281
+ --rtb-content-bg: #1e1e1e;
282
+ --rtb-content-text: #ddd;
283
+ }
284
+ ```
285
+
286
+ > **How it works:** CSS custom properties inherit through shadow boundaries. Any value set on the host element is automatically picked up inside the shadow root — no re-initialization needed.
287
+
288
+ ---
289
+
290
+ ### Toolbar Variables
291
+
292
+ | Variable | Default | Description |
293
+ |---|---|---|
294
+ | `--rtb-toolbar-bg` | `#FFF` | Toolbar background color |
295
+ | `--rtb-toolbar-border-style` | `solid` | Toolbar bottom border style |
296
+ | `--rtb-toolbar-border-width` | `1px` | Toolbar bottom border width |
297
+ | `--rtb-toolbar-border-color` | `#EEE` | Toolbar bottom border color |
298
+ | `--rtb-toolbar-border-radius` | `0px` | Toolbar corner radius (container clips top corners automatically) |
299
+ | `--rtb-dropdown-bg` | `#FFF` | Font / Size / Format dropdown background |
300
+ | `--rtb-dropdown-text` | `#000` | Dropdown item text color |
301
+ | `--rtb-dropdown-bg-hover` | `#e5e5e5` | Dropdown item hover background |
302
+ | `--rtb-dropdown-text-hover` | `#000` | Dropdown item hover text color |
303
+
304
+ ---
305
+
306
+ ### Button Variables
307
+
308
+ | Variable | Default | Description |
309
+ |---|---|---|
310
+ | `--rtb-btn-text` | `#000` | Button icon color |
311
+ | `--rtb-btn-size` | `16px` | Icon size (also drives button `min-height` and divider height) |
312
+ | `--rtb-btn-font` | `Arial, sans-serif` | Font for dropdown buttons |
313
+ | `--rtb-btn-bg` | `inherit` | Button background at rest |
314
+ | `--rtb-btn-bg-hover` | `#DDD` | Button background on hover |
315
+ | `--rtb-btn-bg-selected` | `#CCC` | Button background when active / selected |
316
+ | `--rtb-btn-border-style` | `none` | Button border style |
317
+ | `--rtb-btn-border-width` | `0px` | Button border width |
318
+ | `--rtb-btn-border-color` | `#AAA` | Button border color at rest |
319
+ | `--rtb-btn-border-hover` | `inherit` | Button border color on hover |
320
+ | `--rtb-btn-border-selected` | `inherit` | Button border color when selected |
321
+ | `--rtb-btn-border-radius` | `5px` | Button corner radius |
322
+
323
+ ---
324
+
325
+ ### Content Area Variables
326
+
327
+ | Variable | Default | Description |
328
+ |---|---|---|
329
+ | `--rtb-content-text` | `#000` | Editor text color |
330
+ | `--rtb-content-size` | `16px` | Editor font size |
331
+ | `--rtb-content-font` | `Arial, sans-serif` | Editor font family |
332
+ | `--rtb-content-bg` | `#FFF` | Editor content background color |
333
+ | `--rtb-content-shadow` | `none` | Inner box shadow on the content area |
334
+ | `--rtb-placeholder-color` | `#9ca3af` | Placeholder text color |
335
+
336
+ ---
337
+
338
+ ### Editor Container Variables
339
+
340
+ | Variable | Default | Description |
341
+ |---|---|---|
342
+ | `--rtb-editor-width` | `100%` | Maximum width of the editor |
343
+ | `--rtb-editor-height` | `300px` | Height of the editor |
344
+ | `--rtb-editor-border-style` | `solid` | Outer border style |
345
+ | `--rtb-editor-border-width` | `1px` | Outer border width |
346
+ | `--rtb-editor-border-color` | `#EEE` | Outer border color |
347
+ | `--rtb-editor-border-radius` | `0px` | Outer corner radius |
348
+ | `--rtb-editor-shadow` | `none` | Outer box shadow |
349
+ | `--rtb-editor-resize` | `auto` | `auto` shows the resize handle; `hidden` removes it |
350
+
351
+ ---
352
+
353
+ ### Scrollbar Variables
354
+
355
+ | Variable | Default | Description |
356
+ |---|---|---|
357
+ | `--rtb-scroll-width` | `10px` | Scrollbar track width |
358
+ | `--rtb-scroll-opacity` | `1` | Scrollbar opacity |
359
+ | `--rtb-scroll-bg` | `transparent` | Scrollbar track background |
360
+ | `--rtb-scroll-thumb-bg` | `#AAA` | Scrollbar thumb color |
361
+ | `--rtb-scroll-thumb-bg-hover` | `#DDD` | Scrollbar thumb color on hover |
362
+ | `--rtb-scroll-thumb-radius` | `0` | Scrollbar thumb corner radius |
363
+
364
+ ---
365
+
366
+ ### Blockquote Variables
367
+
368
+ | Variable | Default | Description |
369
+ |---|---|---|
370
+ | `--rtb-quote-bg` | `#f9f9f9` | Blockquote background color |
371
+ | `--rtb-quote-border-color` | `#ccc` | Blockquote left-border color |
372
+ | `--rtb-quote-border-width` | `5px` | Blockquote left-border width |
373
+
374
+ ---
375
+
376
+ ### Code / Pre Variables
377
+
378
+ | Variable | Default | Description |
379
+ |---|---|---|
380
+ | `--rtb-code-bg` | `#f9f9f9` | Code block background color |
381
+ | `--rtb-code-border-radius` | `10px` | Code block corner radius |
382
+
383
+ ---
384
+
385
+ ### Modal / Dialog Variables
386
+
387
+ | Variable | Default | Description |
388
+ |---|---|---|
389
+ | `--rtb-modal-bg` | `#fefefe` | Dialog background color |
390
+ | `--rtb-modal-text` | `#000` | Dialog text and close-button color |
391
+ | `--rtb-modal-text-size` | `16px` | Dialog font size |
392
+ | `--rtb-modal-text-font` | `Arial, sans-serif` | Dialog font family |
393
+ | `--rtb-modal-input-bg` | `#fff` | Input field background |
394
+ | `--rtb-modal-input-text` | `#000` | Input field text color |
395
+ | `--rtb-modal-input-border` | `#CCC` | Input field border color |
396
+ | `--rtb-modal-checkbox` | `#007bff` | Checkbox accent color |
397
+
398
+ ---
399
+
400
+ ## Theming with CSS Classes
401
+
402
+ The cleanest way to create reusable themes is to define a CSS class that overrides the variables you need, then apply it to the element.
403
+
404
+ ```css
405
+ /* styles.css */
406
+ rt-native.dark {
407
+ --rtb-toolbar-bg: #1e1e1e;
408
+ --rtb-toolbar-border-color:#333;
409
+ --rtb-btn-text: #ccc;
410
+ --rtb-btn-bg-hover: #3a3a3a;
411
+ --rtb-btn-bg-selected: #444;
412
+ --rtb-content-text: #ddd;
413
+ --rtb-content-bg: #252526;
414
+ --rtb-editor-border-color: #333;
415
+ --rtb-modal-bg: #2d2d2d;
416
+ --rtb-modal-text: #ccc;
417
+ --rtb-modal-input-bg: #1e1e1e;
418
+ --rtb-modal-input-text: #ccc;
419
+ --rtb-modal-input-border: #555;
420
+ --rtb-dropdown-bg: #2d2d2d;
421
+ --rtb-dropdown-text: #ccc;
422
+ --rtb-dropdown-bg-hover: #3a3a3a;
423
+ }
424
+ ```
425
+
426
+ **Apply via HTML:**
427
+ ```html
428
+ <rt-native class="dark"></rt-native>
429
+ ```
430
+
431
+ **Apply via JavaScript:**
432
+ ```js
433
+ editor.classList.add('dark');
434
+ editor.classList.remove('dark');
435
+ editor.classList.replace('dark', 'ocean');
436
+ ```
437
+
438
+ **Apply via media query (system dark mode):**
439
+ ```css
440
+ @media (prefers-color-scheme: dark) {
441
+ rt-native {
442
+ --rtb-toolbar-bg: #1e1e1e;
443
+ --rtb-content-bg: #252526;
444
+ --rtb-content-text:#ddd;
445
+ /* etc. */
446
+ }
447
+ }
448
+ ```
449
+
450
+ ---
451
+
452
+ ## configure() Reference
453
+
454
+ `configure()` accepts a single options object. Every property is optional. Calling `configure()` multiple times merges with the previous state.
455
+
456
+ ### toolbar options
457
+
458
+ ```js
459
+ editor.configure({
460
+ toolbar: {
461
+ backgroundColor: '#f5f5f5',
462
+ borderStyle: 'solid',
463
+ borderWidth: '1px',
464
+ borderColor: '#ddd',
465
+ borderRadius: '4px',
466
+ dropdownBackgroundColor: '#fff',
467
+ dropdownTextColor: '#000',
468
+ dropdownBackgroundColorHover: '#e5e5e5',
469
+ dropdownTextColorHover: '#000',
470
+ }
471
+ });
472
+ ```
473
+
474
+ ### button options
475
+
476
+ ```js
477
+ editor.configure({
478
+ button: {
479
+ textColor: '#333',
480
+ textSize: '14px',
481
+ textFont: 'Arial, sans-serif',
482
+ backgroundColor: 'transparent',
483
+ backgroundColorHover: '#ddd',
484
+ backgroundColorSelected: '#ccc',
485
+ borderStyle: 'solid',
486
+ borderWidth: '1px',
487
+ borderColor: '#ccc',
488
+ borderColorHover: '#aaa',
489
+ borderColorSelected: '#aaa',
490
+ borderRadius: '4px',
491
+ }
492
+ });
493
+ ```
494
+
495
+ ### content options
496
+
497
+ ```js
498
+ editor.configure({
499
+ content: {
500
+ textColor: '#222',
501
+ textSize: '16px',
502
+ textFont: 'Georgia, serif',
503
+ backgroundColor: '#fff',
504
+ boxShadow: 'none',
505
+ }
506
+ });
507
+ ```
508
+
509
+ ### editor options
510
+
511
+ ```js
512
+ editor.configure({
513
+ editor: {
514
+ width: '100%',
515
+ height: '500px',
516
+ borderStyle: 'solid',
517
+ borderWidth: '1px',
518
+ borderColor: '#ccc',
519
+ borderRadius: '6px',
520
+ boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
521
+ removeResizeHandle: false, // true = hide the resize grip
522
+ }
523
+ });
524
+ ```
525
+
526
+ ### scroll options
527
+
528
+ ```js
529
+ editor.configure({
530
+ scroll: {
531
+ width: '8px',
532
+ opacity: '0.8',
533
+ backgroundColor: 'transparent',
534
+ thumbBackground: '#bbb',
535
+ thumbBackgroundHover:'#888',
536
+ thumbBorderRadius: '4px',
537
+ }
538
+ });
539
+ ```
540
+
541
+ ### modal options
542
+
543
+ ```js
544
+ editor.configure({
545
+ modal: {
546
+ backgroundColor: '#fff',
547
+ textColor: '#000',
548
+ textSize: '15px',
549
+ textFont: 'Arial, sans-serif',
550
+ textboxBackgroundColor: '#fafafa',
551
+ textboxTextColor: '#000',
552
+ textboxBorderColor: '#ccc',
553
+ checkboxAccentColor: '#0066cc',
554
+ }
555
+ });
556
+ ```
557
+
558
+ ### quote options
559
+
560
+ ```js
561
+ editor.configure({
562
+ quote: {
563
+ backgroundColor: '#f9f9f9',
564
+ borderColor: '#ccc',
565
+ borderWidth: '5px',
566
+ }
567
+ });
568
+ ```
569
+
570
+ ### code options
571
+
572
+ ```js
573
+ editor.configure({
574
+ code: {
575
+ backgroundColor: '#f9f9f9',
576
+ borderRadius: '10px',
577
+ }
578
+ });
579
+ ```
580
+
581
+ ### visibility options
582
+
583
+ Controls which toolbar buttons are rendered. All buttons are visible by default except the **status bar** (`wordCount`), which is hidden by default and revealed with the Toggle Status Bar button.
584
+
585
+ Use `clearAll: true` to hide everything first, then opt individual buttons back in.
586
+
587
+ ```js
588
+ // Hide specific buttons
589
+ editor.configure({
590
+ visibility: {
591
+ embedMedia: false,
592
+ table: false,
593
+ imageUpload: false,
594
+ }
595
+ });
596
+
597
+ // Essentials-only toolbar
598
+ editor.configure({
599
+ visibility: {
600
+ clearAll: true, // hide all first
601
+ bold: true,
602
+ italic: true,
603
+ underline: true,
604
+ formatDivider: true,
605
+ alignLeft: true,
606
+ alignCenter: true,
607
+ alignRight: true,
608
+ alignDivider: true,
609
+ undo: true,
610
+ redo: true,
611
+ historyDivider:true,
612
+ htmlView: true,
613
+ preview: true,
614
+ }
615
+ });
616
+ ```
617
+
618
+ **All visibility keys:**
619
+
620
+ | Key | Controls |
621
+ |---|---|
622
+ | `font` | Font family dropdown |
623
+ | `size` | Font size dropdown |
624
+ | `format` | Paragraph / heading format dropdown |
625
+ | `textStylesDivider` | Divider after the three dropdowns |
626
+ | `bold` | Bold button |
627
+ | `italic` | Italic button |
628
+ | `underline` | Underline button |
629
+ | `strikethrough` | Strikethrough button |
630
+ | `subscript` | Subscript button |
631
+ | `superscript` | Superscript button |
632
+ | `formatDivider` | Divider after text-format buttons |
633
+ | `textColor` | Text color, background color, and remove-color buttons |
634
+ | `textColorDivider` | Divider after color buttons |
635
+ | `alignLeft` | Align left button |
636
+ | `alignCenter` | Align center button |
637
+ | `alignRight` | Align right button |
638
+ | `alignJustify` | Justify button |
639
+ | `alignDivider` | Divider after alignment buttons |
640
+ | `cut` | Cut button |
641
+ | `copy` | Copy button |
642
+ | `paste` | Paste button |
643
+ | `delete` | Delete button |
644
+ | `selectAll` | Select all button |
645
+ | `actionDivider` | Divider after clipboard buttons |
646
+ | `orderedList` | Ordered list button |
647
+ | `unorderedList` | Unordered list button |
648
+ | `indent` | Increase / decrease indent buttons |
649
+ | `listDivider` | Divider after list buttons |
650
+ | `link` | Insert link and remove link buttons |
651
+ | `image` | Insert image button |
652
+ | `imageUpload` | Upload / embed image button |
653
+ | `quote` | Block quote button |
654
+ | `codeBlock` | Code block button |
655
+ | `embedMedia` | Embed media (audio / PDF / iframe) button |
656
+ | `video` | Video embed button |
657
+ | `table` | Insert table button |
658
+ | `horizontalRule` | Insert horizontal rule button |
659
+ | `mediaDivider` | Divider after insert buttons |
660
+ | `undo` | Undo button |
661
+ | `redo` | Redo button |
662
+ | `historyDivider` | Divider after undo / redo |
663
+ | `statusBarToggle` | Toggle Status Bar button |
664
+ | `saveHtml` | Save HTML file button |
665
+ | `htmlView` | Toggle HTML source view button |
666
+ | `preview` | Preview button |
667
+ | `wordCount` | Status bar (word / character count) — hidden by default |
668
+
669
+ > **Divider auto-hiding:** Dividers are only rendered when at least one button in their group is visible *and* the divider's own key is `true`.
670
+
671
+ ---
672
+
673
+ ## Preview Window Styling
674
+
675
+ When you load preview CSS with `setPreviewCssFiles()` or `setPreviewCss()`, the component applies the styles in two places simultaneously:
676
+
677
+ 1. **Editor content area** — CSS files are fetched, every selector is automatically prefixed with `.rich-text-box-content`, and the scoped rules are injected into the editor's shadow root. You see your production styles while you type, with no risk of styles escaping to the toolbar, menus, or the surrounding page.
678
+
679
+ 2. **Preview window** — Content is rendered inside an `<iframe srcdoc>` with a completely isolated browsing context. The preview shows exactly what a reader would see in production with a clean browser baseline.
680
+
681
+ ### Using the example stylesheets
682
+
683
+ ```js
684
+ editor.setPreviewCssFiles('preview1.css', 'preview2.css');
685
+ ```
686
+
687
+ | File | Covers |
688
+ |---|---|
689
+ | `preview1.css` | `p`, `strong`, `em`, `h1`–`h6`, `a`, `blockquote`, `code`, `pre` |
690
+ | `preview2.css` | `table`, `thead`, `th`, `td`, `ul`, `ol`, `li`, `img`, `hr` |
691
+
692
+ ### Writing your own preview CSS
693
+
694
+ Write plain CSS — no special selectors, no ID prefixes, no scoping wrappers needed:
695
+
696
+ ```css
697
+ /* my-content.css */
698
+ p {
699
+ font-family: Georgia, serif;
700
+ line-height: 1.8;
701
+ margin-bottom: 1em;
702
+ }
703
+
704
+ h1, h2, h3 { color: #0a2540; }
705
+
706
+ blockquote {
707
+ border-left: 4px solid #0070f3;
708
+ background: #f0f7ff;
709
+ padding: 12px 20px;
710
+ font-style: italic;
711
+ }
712
+ ```
713
+
714
+ ```js
715
+ editor.setPreviewCssFiles('my-content.css');
716
+ ```
717
+
718
+ ### At-rules
719
+
720
+ `@media`, `@supports`, `@layer`, and `@container` blocks are handled correctly — selectors inside them are scoped. Other at-rules (`@keyframes`, `@font-face`, etc.) are passed through unchanged.
721
+
722
+ ---
723
+
724
+ ## Toolbar Buttons
725
+
726
+ Buttons appear left-to-right in the order listed. Dividers separate logical groups.
727
+
728
+ | Button | Action | Shortcut |
729
+ |---|---|---|
730
+ | Font | Set font family | — |
731
+ | Size | Set font size | `Ctrl+Shift+<` / `Ctrl+Shift+>` |
732
+ | Format | Apply block format (paragraph, headings 1–6) | `Ctrl+Shift+D` / `Ctrl+Shift+1`–`6` |
733
+ | Bold | Bold | `Ctrl+B` |
734
+ | Italic | Italic | `Ctrl+I` |
735
+ | Underline | Underline | `Ctrl+U` |
736
+ | Strikethrough | Strikethrough | `Ctrl+D` |
737
+ | Subscript | Subscript | `Ctrl+=` |
738
+ | Superscript | Superscript | `Ctrl+Shift++` |
739
+ | Text Color | Open text color picker | `Ctrl+Shift+C` |
740
+ | Background Color | Open text background color picker | `Ctrl+Shift+B` |
741
+ | Remove Color | Strip text and background color | — |
742
+ | Align Left | Left-align | `Ctrl+L` |
743
+ | Align Center | Center-align | `Ctrl+E` |
744
+ | Align Right | Right-align | `Ctrl+R` |
745
+ | Justify | Justify | `Ctrl+J` |
746
+ | Cut | Cut selection | `Ctrl+X` |
747
+ | Copy | Copy selection | `Ctrl+C` |
748
+ | Paste | Paste from clipboard | `Ctrl+V` |
749
+ | Delete | Delete selection | `Delete` |
750
+ | Select All | Select all content | `Ctrl+A` |
751
+ | Ordered List | Insert numbered list | `Ctrl+Shift+O` |
752
+ | Unordered List | Insert bulleted list | `Ctrl+Shift+U` |
753
+ | Increase Indent | Indent / promote list item | `Tab` |
754
+ | Decrease Indent | Outdent / demote list item | `Shift+Tab` |
755
+ | Insert Link | Open link dialog | `Ctrl+Shift+K` |
756
+ | Remove Link | Remove hyperlink | — |
757
+ | Insert Image | Open image URL dialog | `Ctrl+Shift+I` |
758
+ | Upload Image | Open image upload / embed dialog | `Ctrl+Shift+&` |
759
+ | Block Quote | Open block quote dialog | `Ctrl+Shift+Q` |
760
+ | Embed Media | Open media embed dialog (audio, PDF, iframe) | `Ctrl+Shift+M` |
761
+ | Video | Open video embed dialog | `Ctrl+Shift+V` |
762
+ | Insert Table | Open table dialog | `Ctrl+Shift+L` |
763
+ | Code Block | Open code block dialog | `Ctrl+Shift+*` |
764
+ | Horizontal Rule | Insert `<hr>` at cursor position | `Ctrl+Shift+H` |
765
+ | Undo | Undo last action | `Ctrl+Z` |
766
+ | Redo | Redo last action | `Ctrl+Y` |
767
+ | Toggle Status Bar | Show / hide the word and character count bar | `Ctrl+\` |
768
+ | Save HTML | Download editor content as an `.html` file | `Ctrl+Shift+S` |
769
+ | HTML Source | Toggle raw HTML source view | `Ctrl+Shift+A` |
770
+ | Preview | Open preview dialog | `Ctrl+Shift+P` |
771
+
772
+ ---
773
+
774
+ ## Keyboard Shortcuts
775
+
776
+ All shortcuts are active when the editor content area has focus. The `Ctrl+\` and `Ctrl+Shift+A/P/S` shortcuts also work when the HTML source textarea has focus.
777
+
778
+ | Category | Action | Shortcut |
779
+ |---|---|---|
780
+ | **Formatting** | Bold | `Ctrl+B` |
781
+ | | Italic | `Ctrl+I` |
782
+ | | Underline | `Ctrl+U` |
783
+ | | Strikethrough | `Ctrl+D` |
784
+ | | Subscript | `Ctrl+=` |
785
+ | | Superscript | `Ctrl+Shift++` |
786
+ | **Color** | Text color | `Ctrl+Shift+C` |
787
+ | | Text background color | `Ctrl+Shift+B` |
788
+ | **Alignment** | Align left | `Ctrl+L` |
789
+ | | Align center | `Ctrl+E` |
790
+ | | Align right | `Ctrl+R` |
791
+ | | Justify | `Ctrl+J` |
792
+ | **Editing** | Cut | `Ctrl+X` |
793
+ | | Copy | `Ctrl+C` |
794
+ | | Paste | `Ctrl+V` |
795
+ | | Select all | `Ctrl+A` |
796
+ | | Undo | `Ctrl+Z` |
797
+ | | Redo | `Ctrl+Y` |
798
+ | **Lists** | Ordered list | `Ctrl+Shift+O` |
799
+ | | Unordered list | `Ctrl+Shift+U` |
800
+ | | Increase indent | `Tab` |
801
+ | | Decrease indent | `Shift+Tab` |
802
+ | **Insert** | Insert link | `Ctrl+Shift+K` |
803
+ | | Insert image | `Ctrl+Shift+I` |
804
+ | | Upload image | `Ctrl+Shift+&` |
805
+ | | Block quote | `Ctrl+Shift+Q` |
806
+ | | Video | `Ctrl+Shift+V` |
807
+ | | Embed media | `Ctrl+Shift+M` |
808
+ | | Insert table | `Ctrl+Shift+L` |
809
+ | | Code block | `Ctrl+Shift+*` |
810
+ | | Horizontal rule | `Ctrl+Shift+H` |
811
+ | **Format** | Paragraph | `Ctrl+Shift+D` |
812
+ | | Heading 1–6 | `Ctrl+Shift+1` – `Ctrl+Shift+6` |
813
+ | | Increase font size | `Ctrl+Shift+>` |
814
+ | | Decrease font size | `Ctrl+Shift+<` |
815
+ | **View** | Toggle status bar | `Ctrl+\` |
816
+ | | Toggle HTML source | `Ctrl+Shift+A` |
817
+ | | Preview | `Ctrl+Shift+P` |
818
+ | | Save HTML | `Ctrl+Shift+S` |
819
+
820
+ ---
821
+
822
+ ## Accessibility
823
+
824
+ `rt-native` is built with WCAG 2.1 AA compliance in mind:
825
+
826
+ - **Editor region** — The content area carries `role="textbox"`, `aria-multiline="true"`, and an `aria-label` (defaults to `"Rich text editor"`; override with the `aria-label` or `label` attribute on the host element).
827
+ - **Read-only state** — `aria-readonly` is kept in sync with the `readonly` attribute and `setReadOnly()`.
828
+ - **Toolbar** — The toolbar container has `role="toolbar"` and `aria-label="Formatting toolbar"`. Every button has an `aria-label` derived from its tooltip text (e.g. `"Bold (Ctrl+B)"`) and an `aria-pressed` attribute that is kept in sync with the button's active/selected state.
829
+ - **Status bar** — Carries `role="status"`, `aria-live="polite"`, and `aria-atomic="true"` so word and character count updates are announced non-intrusively by screen readers.
830
+ - **Dialogs** — Every dialog has `aria-modal="true"` and `aria-labelledby` pointing to its title element. Close buttons are native `<button>` elements with descriptive `aria-label` text.
831
+ - **HTML source textarea** — Has `aria-label="HTML source"` to distinguish it from the main editor.
832
+
833
+ ---
834
+
835
+ ## Multiple Instances
836
+
837
+ Each `<rt-native>` element is fully isolated. You can place as many on a page as needed — each gets its own unique ID, shadow root, and state.
838
+
839
+ ```html
840
+ <rt-native id="editor-1" height="200px"></rt-native>
841
+ <rt-native id="editor-2" height="200px" class="dark"></rt-native>
842
+ <rt-native id="editor-3" height="200px"></rt-native>
843
+
844
+ <script src="rt-native.js"></script>
845
+ <script>
846
+ document.getElementById('editor-1').configure({
847
+ visibility: { clearAll: true, bold: true, italic: true }
848
+ });
849
+ document.getElementById('editor-2').setPreviewCssFiles('preview1.css', 'preview2.css');
850
+ document.getElementById('editor-3').configure({ editor: { height: '400px' } });
851
+ </script>
852
+ ```
853
+
854
+ ---
855
+
856
+ ## Browser Support
857
+
858
+ Requires browsers with native support for:
859
+
860
+ - [Custom Elements v1](https://caniuse.com/custom-elementsv1)
861
+ - [Shadow DOM v1](https://caniuse.com/shadowdomv1)
862
+ - [`<dialog>` element](https://caniuse.com/dialog)
863
+ - [CSS Custom Properties](https://caniuse.com/css-variables)
864
+ - [`fetch()`](https://caniuse.com/fetch) *(required for `setPreviewCssFiles()` / `setPreviewCssFile()`)*
865
+
866
+ All modern browsers (Chrome 67+, Firefox 63+, Safari 12.1+, Edge 79+) are supported. Internet Explorer is not supported.