Skip to content

FRD-029: Dense Input/Dropdown Visual Polish

FieldValue
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
Target Releasev2.0.0
TypeRefactor
SizeM
PriorityP1 — Component Improvement

Document Summary

Refactor all input components embedded within dropdowns, popovers, and overlay panels to follow a “flush embedded control” visual rule. Inputs inside overlays should appear integrated with their container (no double borders, consistent padding, shared background) rather than looking like standalone fields dropped into a box. This refactor also ensures dark mode parity for all affected components and codifies the rule in agents.md for future development.


Introduction

Overview

When form inputs (TextField, Select, SearchInput) appear inside dropdowns, popovers, command palettes, or slide-out panels, they often display a visible border against the overlay’s bordered container, creating a “border-on-border” visual artifact. This makes the UI feel unpolished and inconsistent. The design system needs a formalized “flush embedded control” pattern that strips the input’s standalone border and adjusts its padding to integrate with the overlay container.

Goals

  • Define and implement a “flush embedded control” CSS utility class and/or variant that removes standalone input chrome when embedded inside overlays.
  • Apply this rule consistently across all dropdown, popover, command palette, and slide-out panel components that contain inputs.
  • Achieve full dark mode parity for all affected components.
  • Add the “flush embedded control” rule to agents.md so future component development follows it automatically.
  • Ship visual regression stories capturing before/after states.

Non-Goals

  • Redesigning the overlay components themselves (shape, shadow, animation).
  • Changing the standalone appearance of any input component.
  • Adding new input components; this is purely a visual polish refactor.

Scope

In Scope

ItemDescription
Flush embedded control classA CSS utility (flush-embedded or similar) that strips border, adjusts padding, and sets bg-transparent on inputs inside overlays.
Dropdown familyApply flush rule to inputs in Dropdown, DropdownMenu, Combobox, and Command Palette search fields.
Popover familyApply flush rule to inputs inside Popover, DatePicker popover, and filter popovers.
SlideOutPanelApply flush rule to search/filter inputs in SlideOutPanel headers.
ListToolbarApply flush rule to the search input inside ListToolbar when rendered within an overlay context.
Dark mode auditVerify all affected components render correctly in dark mode after the refactor.
agents.md updateAdd the “flush embedded control” rule to the design system operating rules.
Visual regression storiesBefore/after stories for each affected component.

Out of Scope

ItemReason
Modal dialogsInputs in modals are typically in a spacious layout; flush rule is less applicable.
Standalone form pagesNo overlay context; standard input chrome is correct.
New component creationThis is a refactor of existing visual behavior.

Users and Pain Points

UserPain Point
Design system consumersInputs inside dropdowns look inconsistent; teams add custom CSS overrides to fix the double-border.
Designers reviewing implementationsEmbedded inputs don’t match design specs; visual QA catches these repeatedly.
Dark mode usersSome embedded inputs have mismatched backgrounds in dark mode, making them appear to float.
LLM agents building componentsNo codified rule exists; agents recreate the double-border issue in new components.

Definitions

TermDefinition
Flush embedded controlAn input control rendered without its standalone border and background, visually merging with its parent overlay container.
Double borderThe visual artifact where an input’s border renders adjacent to or against an overlay’s border, creating a heavy or doubled line.
Overlay contextAny component that renders as a floating layer: dropdowns, popovers, command palettes, slide-out panels.
Field shellThe styled container (getFieldShellClassName) that provides border, background, and focus ring to form inputs.

Current State

  • getFieldShellClassName (src/lib/form-control-styles.ts): Generates the border, background, padding, and focus ring classes for all form inputs. Does not have an “embedded” or “flush” variant.
  • dropdownOverlayPanelClassName (src/components/ui/dropdowns/dropdown-hooks.ts): Shared class for dropdown/popover overlay panels. Applies its own border and background.
  • DatePicker popover: Contains a calendar but no embedded input currently.
  • Combobox / Command Palette: Contains a search TextField at the top of the dropdown; currently shows double border.
  • ListToolbar: Contains a search input; when rendered inside a SlideOutPanel, the input border doubles with the panel border.
  • Dark mode: Most components technically support dark mode via tokens, but some embedded inputs have subtle background mismatches.

Proposed Solution

Define the flush variant

Add a flush variant to getFieldShellClassName in src/lib/form-control-styles.ts:

// When flush is true: border-transparent, bg-transparent, shadow-none, px-0
getFieldShellClassName({ size, disabled, error, flush: true })

This strips the standalone chrome while preserving focus ring behavior (focus ring applies to the overlay container or the input directly, depending on context).

Apply contextually

Each overlay component that embeds an input passes flush to the input (or wraps it in a context provider that signals “you are embedded”). Candidate approach: a FormControlContext with { embedded: boolean } that field shells read automatically. This avoids threading a prop through every component tree.

Component-by-component changes

  • Combobox search input: Auto-flush via context when inside dropdown panel.
  • Command Palette search input: Auto-flush; adjust top padding to align with panel padding.
  • ListToolbar in SlideOutPanel: Detect overlay ancestor via context; flush the search input.
  • Filter popovers: Any TextField or Select inside a popover reads the embedded context.

Dark mode audit

After applying flush, audit all affected components in dark mode. The overlay’s bg-card or bg-popover token is the source of truth; inputs inherit it via bg-transparent.

Codify in agents.md

Add a rule under the design-system operating rules:

Flush embedded control rule: Any form input rendered inside a dropdown, popover, command palette, or slide-out panel must use the flush field shell variant. The input’s border, background, and padding must integrate with the overlay container rather than rendering standalone chrome. This prevents border-on-border artifacts and ensures dark mode parity.


Requirements

Requirement Priorities

  • Must Have: Flush variant in field shell, applied to Combobox and Command Palette.
  • Should Have: FormControlContext for automatic flush detection, applied to all overlay families.
  • Could Have: Animated border-fade transition when an input moves from standalone to embedded context.

Functional Requirements

IDRequirementPriority
FR-01getFieldShellClassName accepts a flush boolean that removes border, background, and shadow.Must
FR-02Combobox search input renders flush inside its dropdown panel.Must
FR-03Command Palette search input renders flush inside its overlay.Must
FR-04ListToolbar search input renders flush when inside a SlideOutPanel.Should
FR-05FormControlContext provides { embedded: boolean } to descendants of overlay components.Should
FR-06Field shells automatically apply flush styling when embedded is true in context.Should
FR-07Focus ring remains visible on flush inputs (applied to the input element directly, not a border wrapper).Must
FR-08All affected components render correctly in dark mode with no background mismatches.Must
FR-09agents.md is updated with the flush embedded control rule.Must

Non-Functional Requirements

IDRequirementTarget
NFR-01No visual regression in standalone input appearance.Zero pixel-level changes to non-embedded inputs.
NFR-02No bundle size increase from the context provider.< 200 bytes gzipped.
NFR-03Dark mode parityAll affected components pass visual inspection in both themes.

API/Interface Requirements

getFieldShellClassName extension

interface FieldShellOptions {
size?: "sm" | "md" | "lg";
disabled?: boolean;
error?: boolean;
flush?: boolean; // NEW — removes standalone chrome
}

FormControlContext

interface FormControlContextValue {
embedded: boolean;
}
const FormControlContext = React.createContext<FormControlContextValue>({ embedded: false });

Overlay components (Popover, DropdownPanel, SlideOutPanel) wrap children with &lt;FormControlContext.Provider value={{ embedded: true }}&gt;.


Accessibility Requirements

IDRequirement
A11Y-01Focus ring remains visible on flush inputs; it must meet 3:1 contrast ratio against the overlay background.
A11Y-02No change to ARIA attributes on any affected input.
A11Y-03Screen reader experience is unchanged; labels and descriptions remain linked.

Content and Documentation Requirements

IDRequirement
DOC-01Update agents.md with the “flush embedded control” rule.
DOC-02Storybook stories showing embedded vs. standalone inputs side by side.
DOC-03Migration guide for teams that have manually overridden embedded input styling.

Dependencies

DependencyTypeRisk
src/lib/form-control-styles.tsInternalLow — adding a variant to existing utility.
All overlay componentsInternalMedium — multiple files touched, but changes are CSS-only.
src/styles/motion.cssInternalLow — no motion changes needed.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
Flush variant accidentally applied in non-overlay contextsLowMediumContext-based detection ensures flush only activates inside overlays; manual flush prop is opt-in only.
Visual regression in existing componentsMediumHighChromatic or Percy visual regression tests on all affected stories.
FormControlContext overhead in deeply nested treesLowLowContext value is a static object; no re-renders unless overlay mounts/unmounts.

Open Questions

#QuestionOwnerStatus
OQ-01Should flush apply to Modal dialog inputs or only overlay/dropdown contexts?David HolmesOpen
OQ-02Should the context provider be named FormControlContext or OverlayContext (broader)?David HolmesOpen
OQ-03Should flush inputs have a subtle bottom-border separator instead of fully borderless?David HolmesOpen

Acceptance Criteria

#Criterion
AC-01getFieldShellClassName({ flush: true }) produces classes without border, background, or shadow.
AC-02Combobox and Command Palette search inputs render without double-border artifacts.
AC-03All affected components render correctly in dark mode with no background mismatches.
AC-04Standalone inputs are visually unchanged (zero regression).
AC-05Focus ring is visible on flush inputs with 3:1+ contrast ratio.
AC-06agents.md contains the flush embedded control rule.
AC-07Visual regression stories exist for all affected components.
AC-08pnpm typecheck and pnpm vitest run --project unit pass with zero errors.

LLM Handoff Instructions

When implementing this FRD:

  1. Start with getFieldShellClassName in src/lib/form-control-styles.ts. Add a flush option that conditionally omits border, background, and shadow classes. Test by rendering a TextField with flush in a Storybook story.
  2. Then add FormControlContext in a new file src/lib/form-control-context.tsx (or add to an existing context file). Provide it from overlay components: Popover, DropdownPanel (in dropdown-hooks.ts), SlideOutPanel.
  3. Then modify the field shell to read from FormControlContext when flush is not explicitly passed — if embedded is true in context, auto-apply flush.
  4. Then audit each overlay component that contains inputs: Combobox, Command Palette, ListToolbar, filter popovers. Verify the flush rule applies. Check dark mode.
  5. Update agents.md with the flush embedded control rule under the design-system operating rules section.
  6. Add visual regression stories showing embedded inputs in each overlay type.

Key files to modify:

  • src/lib/form-control-styles.ts — add flush variant.
  • src/components/ui/dropdowns/dropdown-hooks.ts — provide FormControlContext.
  • src/components/ui/slide-out-panel.tsx — provide FormControlContext.
  • src/components/ui/popover.tsx (or equivalent) — provide FormControlContext.
  • agents.md — add the rule.

Decision Log

DateDecisionRationale
2026-05-26Use a React context for automatic flush detection rather than requiring an explicit prop on every input.Reduces consumer burden; overlay components manage the context, inputs read it automatically.
2026-05-26Keep flush as an explicit prop override in addition to context.Some edge cases need manual control (e.g., an input inside a popover that should NOT be flush).
2026-05-26Codify the rule in agents.md to prevent recurrence.LLM agents and human developers need a single source of truth for this visual pattern.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.