Skip to content

LayrzSearchInput

Kenny Mochizuki Escalona edited this page Aug 24, 2026 · 3 revisions

LayrzSearchInput

Text search field with optional inline or overlay presentation.

Specification Status: Derived from layrz_theme.ThemedSearchInput. This documentation reflects the current layrz_theme API and is NOT YET CONFIRMED as the design for layrz_ui. Team review and design sign-off are required before implementation.

Metadata

Property Value
Mirror ThemedSearchInput
Phase M3 Inputs
Domain Inputs
SDK Primitive EditableText (with optional Overlay for expansion)

Conformance Status

Open question: LayrzSearchInput does NOT obviously compose LayrzTextInput like the picker-style inputs. In overlay form, the search surface appears in an overlay above the button; in field form, it is an inline field. Should both forms compose a read-only LayrzTextInput as a display surface? See open questions below.

Value Type and Selection Surface

  • Value type: String — the search query text
  • Interaction pattern:
    • Overlay form (compact icon button): A magnifying glass icon; on tap, expands into an overlay with a text input field
    • Field form (inline): A full-width text field with a search icon prefix
  • Summary display: The field displays the current search query (or empty if not searching)

Deltas from the Input Contract

LayrzSearchInput differs from the picker-style inputs in that it offers two distinct presentation modes, not one. The choice is made at construction time:

// Design sketch — illustrative only
class LayrzSearchInput extends StatefulWidget {
  /// The current search query text.
  final String value;

  /// Callback invoked when the search query changes.
  /// Debounce can be applied (see [debounce] parameter).
  final void Function(String)? onSearch;

  /// Label or placeholder text for the search field.
  final String labelText;

  /// Presentation mode: field (inline) or button (overlay).
  final LSearchPosition position;

  /// Whether to render as an inline field (true) or compact button (false).
  final bool asField;

  /// Maximum width of the search field/overlay.
  final double maxWidth;

  /// Debounce duration for search callbacks.
  /// If null, no debounce is applied.
  /// Defaults to 300 milliseconds.
  final Duration? debounce;

  /// Whether the search is disabled.
  final bool disabled;

  /// Custom widget to replace the entire search UI.
  final Widget? customChild;

  const LayrzSearchInput({
    required this.value,
    required this.onSearch,
    this.labelText = 'Search',
    this.position = .left,
    this.asField = false,
    this.maxWidth = 300,
    this.debounce = const Duration(milliseconds: 300),
    this.disabled = false,
    this.customChild,
  });
}

enum LSearchPosition {
  /// Overlay expands to the left of the button.
  left,

  /// Overlay expands to the right of the button.
  right,
}

Inherits from Input Contract?

Open question: LayrzSearchInput does not currently follow the input contract pattern. It does not use LayrzTextInput internally, nor does it expose the contract's standard API (label, prefix, suffix, help affordances, focus management).

Should layrz_ui redesign it to:

  • Always compose a text field (whether overlay or inline)?
  • Inherit standard input contract API (help affordance, padding, etc.)?
  • Or keep the current minimal surface and treat it as a specialized component?

Reference: Current layrz_theme API

ThemedSearchInput (source: lib/src/inputs/src/general/search_input.dart):

Parameter Type Notes
value String Current search query
onSearch OnSearch (void Function(String)) Search callback
maxWidth double Max width of field/overlay (default: 300)
labelText String Field label/placeholder (default: "Search")
customChild Widget? Replace entire search UI with custom widget
disabled bool Disable the search (default: false)
position ThemedSearchPosition Overlay direction: left or right (default: left)
asField bool Render as field instead of button (default: false)
inputPadding EdgeInsets Padding for field form only (default: EdgeInsets.zero)
debounce Duration? Debounce delay for onSearch (default: 300ms)

ThemedSearchPosition enum:

  • left: Overlay appears to the left
  • right: Overlay appears to the right

layrz_ui Additions Beyond the Mirror

DESIGN-142 moved LayrzSearchInput off wrapping LayrzTextInput and onto composing LayrzInputChrome directly (see decision D63). Going through the chrome directly gave the field five parameters ThemedSearchInput never had — before this, LayrzSearchInput could not display a validation error at all:

Parameter Type Notes
errors List<String> Error messages shown below the field. Non-empty renders a danger-colored border, a trailing error icon, and the messages themselves. Defaults to const [].
isRequired bool Renders a required marker (*) next to labelText in field mode. No visible effect in icon mode, where the panel field renders no label. Defaults to false.
helpTitleText String? Title text for the help affordance tooltip. Ignored unless helpContentText is also set.
helpContentText String? Content text for the help affordance tooltip. When set (and non-empty), a help icon appears in the trailing icon cluster.
readOnly bool Field is not editable but still fires tap callbacks, and renders a lock affordance in the trailing icon cluster. Does not affect the clear button. Defaults to false.

All five are additive and non-breaking — they were not part of the ThemedSearchInput mirror table above.

Behavioral fix — clear icon now appears while typing

Before DESIGN-142, the clear affordance in field mode only appeared when the field was seeded with an initial value — typing into an initially-empty field never made it show up, because the widget read the controller's text once but never listened for changes on it. The controller now carries a listener that triggers a rebuild on the empty/non-empty transition (not on every keystroke), so the clear icon correctly appears as soon as the user types a character and disappears again once the field is cleared. The listener is removed in dispose before the widget's own conditional controller disposal, so a caller-supplied controller is still never disposed by this widget.

Dependencies and Blockers

  • LayrzTextInput — only if redesigned to always compose it (see open questions)
  • Material-free TextSelectionControls — required for copy/paste in the search field

Implementation Notes from layrz_theme

  • Overlay positioning: The overlay is smart-positioned based on available screen space. If position is left but there isn't enough space on the left, the overlay is repositioned to the right.
  • Escape key handling: Pressing Escape closes the overlay.
  • Debounce: If debounce is null, onSearch is invoked immediately on every keystroke. Otherwise, it fires after the debounce duration.
  • Form vs. button rendering: asField: true renders the search input inline with a specified inputPadding. asField: false renders as a 40×40 icon button.

Open Questions

  1. Composition pattern: Should LayrzSearchInput be redesigned to always compose LayrzTextInput, bringing it into the input family contract? Or is the current minimal surface appropriate for layrz_ui?

  2. Form support: If redesigned to compose LayrzTextInput, does it inherit the full contract (label, placeholder, prefix/suffix, help affordances)?

  3. Overlay vs. field naming: If both forms are kept, should they be:

    • Factory constructors (e.g., LayrzSearchInput() for overlay, LayrzSearchInput.field() for inline)?
    • Or a single constructor with a boolean flag?
  4. Position parameter purpose: In the overlay form, position is used to indicate which side of the button the overlay expands toward. In the field form, does this parameter have any meaning?

  5. Keyboard management: Are Tab, Shift+Tab, Enter, and Escape supported for keyboard navigation and submission?

  6. Search trigger: Is there a "search" or "clear" button in the overlay/field, or only auto-trigger on debounce?

  7. Accessibility: Does the overlay escape key behavior work with screen readers? Should there be a close button visible?


Last updated: 2026-08-13
Related documents: Input Contract, Component Catalog, Design Tokens

Clone this wiki locally