lazy_text_field 1.0.3 copy "lazy_text_field: ^1.0.3" to clipboard
lazy_text_field: ^1.0.3 copied to clipboard

Pure-Flutter lazy text fields for table and grid cells with exact constrained-width height measurement.

lazy_text_field #

Tests pub package License: MIT

Pure Flutter lazy text-field primitives for table and grid cells.

LazyTextField renders read-only text without allocating edit resources, then connects a real TextField only while editing. It also exposes fast constrained-width height calculation through LazyTextFieldLayout, LazyTextFieldMetrics, and LazyTextField.computeHeightForWidth.

Live demo #

Explore the full table demo in the browser:

Open the live demo

The live demo covers edit-only and always-visible decoration, constrained wrapping, bounded height with scrollbar gutter, prefix/suffix icons, overflow markers, and lazy controller allocation in a multi-column table.

Even on the full page, only one real TextField / EditableText is mounted at a time. Every other cell stays on the lightweight read-only path until it is activated.

Run the same demo locally with:

cd example
flutter run -d chrome -t lib/main_live_demo.dart

Installation #

Add lazy_text_field to your pubspec.yaml:

dependencies:
  lazy_text_field: ^1.0.3

Then import the public barrel:

import 'package:lazy_text_field/lazy_text_field.dart';

Why not just TextField? #

TextField in every cell LazyTextField
Controllers / focus nodes One per visible cell Created only for the active editor
Read-only rendering Still pays InputDecorator layout cost Lightweight Text / painter path
Static to edit switch Often shifts line wraps or height Keeps the same text layout boxes
Row height in tables Hard to match edit height exactly computeHeightForWidth uses the same engine as the widget
Decoration in grids InputDecoration affects intrinsic height LazyInputDecoration is height-neutral chrome

Use LazyTextField when you render hundreds or thousands of editable cells and need predictable memory use, stable row heights, and pixel-aligned transitions between read-only and edit modes.

The real cost is the mounted TextField #

For big tables and grids, the expensive part is not just text painting. The cost appears when every visible cell mounts a real TextField.

A Flutter TextField builds an EditableText. EditableTextState participates in a lot of editing infrastructure, including:

  • TextInputClient
  • AutofillClient
  • WidgetsBindingObserver
  • TickerProviderStateMixin
  • AutomaticKeepAliveClientMixin
  • text-selection behavior
  • clipboard monitoring
  • spell-check behavior
  • cursor animation
  • scrolling
  • keyboard input connection
  • selection overlays and context menus

During initialization, EditableTextState registers controller and focus listeners, clipboard listeners, lifecycle handling, spell-check configuration, and other editing infrastructure. EditableText also handles keyboard input through the platform text-input service, selection and cursor movement, keeping the caret visible, scrolling, input formatters, selection menus, and gestures.

That is all correct for the active editor. It is unnecessary for thousands of read-only cells. LazyTextField keeps the table cheap by rendering static cells with a lightweight text path, then mounting the real TextField only for the cell currently being edited.

Choose a widget #

Widget When to use
LazyTextField You already own controller/focus state and pass them only while editing
StatefulLazyTextField One-off cell where the widget can own its edit lifecycle
LazyTextFieldControllerScope + ScopedLazyTextField Many cells sharing one edit manager

Usage #

LazyTextField(
  cellId: 'row-42-title',
  text: value,
  isEditing: controller != null && focusNode != null,
  controller: controller,
  focusNode: focusNode,
  style: const TextStyle(fontSize: 14, height: 1.25),
  padding: kDefaultLazyTextFieldPadding,
  decoration: LazyInputDecoration(
    filled: true,
    border: const OutlineInputBorder(),
    hintText: 'Click to edit',
    prefixIcon: const Icon(Icons.notes, size: 16),
    prefixIconConstraints: const BoxConstraints(minWidth: 28),
  ),
  decorationVisibility: LazyInputDecorationVisibility.editing,
  onStartEditing: startEditing,
  onChanged: updateDraft,
)

When isEditing is true, provide both controller and focusNode. When it is false, pass null for both so read-only mode stays lazy.

For simple local state, use StatefulLazyTextField. For many cells sharing one edit manager, wrap a subtree in LazyTextFieldControllerScope and use ScopedLazyTextField.

StatefulLazyTextField and ScopedLazyTextField can control the initial selection with startEditSelection: beginning, end, tapPosition, or fullSelection.

Decoration #

LazyInputDecoration is height-neutral chrome drawn outside the internal TextField, which always receives decoration: null. Supported fields are fill, hover/focus/error/disabled borders, hint text/style, prefix icon, suffix icon, and icon constraints.

Decoration does not add padding. LazyTextField.padding is the only content padding source.

Overflow marker #

When read-only text is clipped, LazyTextField shows a default red corner marker. Customize it with overflowMarkerBuilder, or pass null to hide it:

LazyTextField(
  cellId: 'row-42-notes',
  text: value,
  isEditing: false,
  onStartEditing: startEditing,
  overflowMarkerBuilder: (context, details) {
    return Icon(
      details.expanded ? Icons.unfold_less : Icons.more_horiz,
      size: details.size,
      color: details.color,
    );
  },
)

The package still owns marker positioning and tap handling, so marker taps call onReadOnlyOverflowToggle without also starting cell editing. Use LazyTextField.defaultOverflowMarkerBuilder to delegate back to the default triangle from a custom builder.

Height Measurement #

final height = LazyTextField.computeHeightForWidth(
  text: value,
  width: columnWidth,
  style: const TextStyle(fontSize: 14, height: 1.25),
  padding: kDefaultLazyTextFieldPadding,
  reservedLeadingWidth: 28,
  reservedTrailingWidth: 28,
);

The layout path uses TextPainter, the effective text width, strut style, text direction, text scaler, a zero-width space for empty text and trailing newlines, and ceiled final heights.

For bounded editing, scrollbarGutter reserves text width for the package scrollbar. Use scrollbarThickness and scrollbarAlignment to control the thumb size and where it sits inside that reserved gutter.

License #

MIT - see LICENSE.

1
likes
160
points
135
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Pure-Flutter lazy text fields for table and grid cells with exact constrained-width height measurement.

Repository (GitHub)
View/report issues

Topics

#flutter #text-field #datatable #grid #performance

License

MIT (license)

Dependencies

flutter

More

Packages that depend on lazy_text_field