val_highlight_flutter
Syntax-highlighted code for Flutter.
Show code with CodeView and edit it with CodeField.
55 languages, eight themes, and large files that stay smooth.
โ๏ธ Engine ยท ๐ป GitHub ยท ๐ฆ pub.dev
โจ Why val_highlight_flutter?
- Two widgets, one line each โ
CodeView(source, language: dartLanguage)to show code,CodeField(controller: โฆ)to edit it. - Smooth on large files โ a 20,000-line file scrolls with no dropped frames, and typing in a 2,000-line editor takes about 14 ms per keystroke.
- Real editing โ auto-closing brackets and quotes, comment toggling, bracket matching, smart indentation and line numbers, on every keyboard; every edit re-highlights only what it can affect.
- Native rendering โ plain Flutter text, no WebView and no platform code. Works on Android, iOS, macOS, Windows, Linux and the web.
- Follows your app โ light and dark themes switch with the app, and
CodeThemesets defaults once for every code block. - Interactive โ tap handlers and custom spans per token, for jump-to-definition, links and tooltips.
๐ ๏ธ Quick start
flutter pub add val_highlight_flutter
import 'package:val_highlight_flutter/val_highlight_flutter.dart';
import 'package:val_highlight/languages/dart.dart';
CodeView(source, language: dartLanguage)
This package re-exports the core API of
val_highlight. Languages and
themes are separate imports under package:val_highlight/languages/ and
package:val_highlight/themes/, so an app ships only what it uses.
๐ CodeView
CodeView(
source,
language: kotlinLanguage,
lineNumbers: true,
highlightedLines: {3, 4},
wrap: true,
header: const Text('MainActivity.kt'),
onTokenTap: (token) => print('${token.scope}: ${token.text}'),
)
- Line numbers โ
lineNumbers,firstLineNumber; a customgutterBuilder. - Highlighted lines โ
highlightedLines,highlightColor. - Wrapping โ
wrap: true, or scroll long lines horizontally. - Selection and copying โ on by default (
selectable); line numbers are never copied. - Custom rendering โ
lineBuilderwraps each row,headeradds a title bar or copy button,spanBuilderreplaces any token's span. - Tappable tokens โ
onTokenTapreceives each token's text, offsets, line and scopes. - Unknown languages โ with no
language, passdetectLanguages: allLanguagesto detect it; otherwise the generic grammar highlights what most languages share (fallbackLanguagechanges this). - Large files โ code with more than
virtualizeAbovelines (1,000 by default), placed where its height is bounded, renders lazily. Inputs above 50,000 characters are highlighted in a background isolate while plain text shows.
โจ๏ธ CodeField
final controller = HighlightTextController(language: dartLanguage);
CodeField(controller: controller, expands: true)
CodeField is a TextField for code:
- monospace, no autocorrect or smart quotes;
- brackets and quotes close themselves, typing a closer steps over it, and Backspace deletes an empty pair;
- typing a bracket or quote over a selection wraps it;
- Enter keeps the current indentation, adding a level after
{,[,(or:, and moves the closer of{|}onto its own line; - Tab and Shift+Tab indent and outdent (
indentsets the unit); - Ctrl+/ (Cmd+/ on Apple platforms) comments and uncomments lines;
- the bracket at the caret and its match are outlined;
- each edit re-scans only the lines it can affect.
Brackets, quotes and comment markers come from the language
(EditingSyntax), so Rust lifetimes or Python # comments behave. Typing
is handled as text changes rather than key presses, so it works the same
on hardware keyboards, on-screen keyboards and voice input, and never
touches text an input method is still composing.
CodeField(
controller: controller,
lineNumbers: true,
highlightCurrentLine: true,
highlightedLines: {3, 4},
editing: const CodeEditing(autoClose: false), // or CodeEditing.none
)
Line numbers and line bands are painted from the text's own layout, so wrapped lines line up, and only visible lines are painted.
Each shortcut sends an intent: IndentCodeIntent, OutdentCodeIntent or
ToggleCommentIntent. Rebind keys with shortcuts (const {} gives Tab
back to focus traversal), or change what an intent does with an Actions
widget above the field:
Actions(
actions: {
ToggleCommentIntent: CallbackAction<ToggleCommentIntent>(
onInvoke: (_) => myToggle(),
),
},
child: CodeField(controller: controller),
)
For a plain TextField, add
CodeEditingFormatter(controller: controller) to its inputFormatters to
get the same typing behaviour.
Flutter lays out a text field's whole text on every change, and styled runs
make that slower. So for documents over 300 lines, CodeField colours only
the visible lines plus a margin, and the coloured window follows scrolling.
HighlightTextController also works in a plain TextField for short
documents. For long ones, use CodeField, or set controller.window
yourself.
๐จ Themes
The theme follows the app's brightness: lightTheme or darkTheme by
default. Choose any of the eight built-in themes, a VS Code theme, or your
own:
CodeView(source, language: dartLanguage, theme: midnightTheme)
Set app-wide defaults once:
MaterialApp(
theme: ThemeData(
extensions: [
CodeTheme(
light: sepiaTheme,
dark: dimTheme,
textStyle: const TextStyle(fontFamily: 'JetBrains Mono'),
lineNumbers: true,
),
],
),
)
โ๏ธ CodeHighlighter
CodeHighlighter.shared highlights for every widget, with a result cache.
Create your own to change the isolate threshold or cache size, or to resolve
languages named inside code, such as Markdown fences:
final highlighter = CodeHighlighter(registry: allLanguagesRegistry());
CodeView(markdown, language: markdownLanguage, highlighter: highlighter)
Call CodeHighlighter.shared.preload([dartLanguage, โฆ]) at startup to
compile languages during idle frames, so the first code shown in each has no
compile delay (1โ3 ms per language otherwise).
๐งฑ Lower level
CodeStylesconverts aValThemeinto cachedTextStyles.lineSpans,documentSpansandexactSpansturn aHighlightResultintoTextSpans for your own widgets.
๐ธ Screenshots
![]() CodeView Line numbers, highlighted lines, selection. |
![]() CodeField An editor that highlights as you type. |
![]() Languages inside languages Markdown fences, HTML with CSS and JavaScript. |
|---|
โก Performance
Frame timings on a MacBook, in profile mode:
| Scenario | Build time avg / p90 | Missed frames |
|---|---|---|
Scroll a 20,000-line CodeView |
1.3 / 2.6 ms | 0 of 926 |
| Same, wrapped | 1.3 / 2.6 ms | 0 of 927 |
| Scroll 800 lines as one text block | 0.3 / 0.4 ms | 0 of 915 |
Type in a 2,000-line CodeField |
14.3 / 15.7 ms | 4 of 120 |
Type in a plain TextField, same text, no highlighting |
17.4 / 17.6 ms | 120 of 120 |
Scroll a 2,000-line CodeField |
3.7 / 7.1 ms | 15 of 926 |
The missed frames while scrolling a CodeField happen when its coloured
window moves, which makes Flutter lay out the whole field again.
๐งช Example
The example app has a gallery of every language and theme, a live editor, and a large file rendered lazily.
Built by Val
val_highlight_flutter is part of Val, the live visual
layer for AI agents.
๐ฌ Community
Issues and pull requests are welcome on GitHub; see the contributing guide. If the package helps your project, consider giving it a like on pub.dev or a star on GitHub.
๐ License
BSD 3-Clause โ see LICENSE.
Libraries
- val_highlight_flutter
- Flutter widgets for
val_highlight.


