Code Editor overview
Code Editor combines a native textarea with an aria-hidden highlighted overlay. Editing, selection, clipboard, undo, and IME behavior remain native while highlighting stays adapter-based.
Imports and provider
The component works without a highlighter and renders escaped plain text by default.
Component import
ts
import { TngCodeEditorComponent } from '@tailng-ui/components';Optional highlighting provider
ts
provideTngCodeHighlighting({
adapters: [shikiCodeHighlighterAdapter],
defaultAdapter: 'shiki',
});Editable source
Compare the same code-editor contract in Plain CSS and Tailwind CSS layouts. Each example includes HTML, CSS, and TypeScript source.
Code Editor (Plain CSS)
code-editor-plain-example.component.ts
ts
import { Component, signal } from '@angular/core';
import { TngCodeEditorComponent } from '@tailng-ui/components';
@Component({
selector: 'app-code-editor-plain-example',
imports: [TngCodeEditorComponent],
templateUrl: './code-editor-plain-example.component.html',
styleUrl: './code-editor-plain-example.component.css',
})
export class CodeEditorPlainExampleComponent {
protected readonly source = signal(
'def greet(name: str) -> str:\n return f"Hello, {name}!"',
);
protected readonly codeTheme = signal<'github-dark' | 'github-light'>('github-light');
}code-editor-plain-example.component.html
html
<section class="code-editor-example">
<div class="code-editor-example__heading">
<label for="python-source">Python source</label>
<span>{{ source().length }} characters</span>
</div>
<tng-code-editor
id="python-source"
language="python"
adapter="shiki"
ariaLabel="Python source"
[theme]="codeTheme()"
[sanitizeHtml]="false"
[rows]="9"
[value]="source()"
(valueChange)="source.set($event)"
/>
</section>code-editor-plain-example.component.css
css
.code-editor-example {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--tng-semantic-border-subtle);
border-radius: 0.875rem;
background: var(--tng-semantic-background-surface);
}
.code-editor-example__heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.code-editor-example__heading label {
color: var(--tng-semantic-foreground-primary);
font-weight: 650;
}
.code-editor-example__heading span {
color: var(--tng-semantic-foreground-muted);
font-size: 0.75rem;
}81 characters
Code Editor (Tailwind CSS)
code-editor-tailwind-example.component.ts
ts
import { Component, signal } from '@angular/core';
import { TngCodeEditorComponent } from '@tailng-ui/components';
@Component({
selector: 'app-code-editor-tailwind-example',
imports: [TngCodeEditorComponent],
templateUrl: './code-editor-tailwind-example.component.html',
styleUrl: './code-editor-tailwind-example.component.css',
})
export class CodeEditorTailwindExampleComponent {
protected readonly source = signal(
'export function greet(name: string): string {\n return `Hello, ${name}!`;\n}',
);
protected readonly codeTheme = signal<'github-dark' | 'github-light'>('github-light');
}code-editor-tailwind-example.component.html
html
<section class="grid gap-3 rounded-2xl border border-[var(--tng-semantic-border-subtle)] bg-[var(--tng-semantic-background-surface)] p-4">
<div class="flex items-center justify-between gap-4">
<label for="typescript-source" class="font-semibold text-[var(--tng-semantic-foreground-primary)]">
TypeScript source
</label>
<span class="text-xs text-[var(--tng-semantic-foreground-muted)]">
{{ source().length }} characters
</span>
</div>
<tng-code-editor
id="typescript-source"
language="ts"
adapter="shiki"
ariaLabel="TypeScript source"
[theme]="codeTheme()"
[sanitizeHtml]="false"
[rows]="9"
[value]="source()"
(valueChange)="source.set($event)"
/>
</section>code-editor-tailwind-example.component.css
css
/* No component CSS is required; Tailwind utilities style the example shell. */ 109 characters
Component boundaries
tng-textareais for ordinary plain and multiline form text.tng-code-editoris for editable source with optional highlighting.tng-code-blockis for read-only rendered source.
Accessibility baseline
- The native textarea is the only interactive and accessibility surface.
- The highlighted layer is always hidden from assistive technology.
- Tab keeps its native focus-navigation behavior and is not trapped.
- Readonly content remains focusable and selectable; disabled content does not.