Skip to content

feat(components): add Textarea component#313

Merged
desmondinho merged 19 commits into
mainfrom
feat/textarea
May 14, 2026
Merged

feat(components): add Textarea component#313
desmondinho merged 19 commits into
mainfrom
feat/textarea

Conversation

@desmondinho
Copy link
Copy Markdown
Contributor

@desmondinho desmondinho commented May 14, 2026

Closes #117

Description

Adds LumexTextarea — the multi-line counterpart of LumexTextbox.

What's been done?

  • Component. LumexTextarea with new parameters: MinRows (default 3), MaxRows (default 8), DisableAutosize. Renders <textarea> with value bound via the value attribute (matches Microsoft's InputTextArea — content-as-value desyncs on re-render).
  • Autosize. New wwwroot/js/components/textarea.js clamps height between minRows and maxRows line-heights on each input event. Skipped entirely when DisableAutosize is set so the user owns sizing without JS interference.
  • data-autosize-disabled attribute. Drives a conditional transition-[height] so dragging the native resize handle (when overridden in user CSS) isn't laggy.
  • All gated on a runtime input is LumexTextarea type check rather than a Multiline flag on the base — LumexTextbox / LumexNumbox / LumexDatebox get no new members and no "multiline" concept on their surface.
  • Tests. tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor: rendering, <textarea> element + value-attribute binding, slot wiring, clear button, debounce delay & behavior, OnInput vs OnChange semantics, MinRows on the rows attribute, label-outside-input-wrapper placement.
  • Docs. Full mirror of the Textbox page at docs/LumexUI.Docs.Client/Pages/Components/Textarea/ (16 examples) plus a new Autosize example demonstrating MinRows / MaxRows / DisableAutosize. Registered in NavigationStore (sidebar + API) and llms.txt.

Checklist

  • My code follows the project's coding style and guidelines.
  • I have included inline docs for my changes, where applicable.
  • I have added, updated or removed tests according to my changes.
  • All tests are passing.
  • There's an open issue for the PR that I am making.

Additional Notes

Summary by CodeRabbit

  • New Features

    • Added LumexTextarea component with autosizing, customizable rows, clear button, and validation support.
    • Supports multiple variants, sizes, colors, radius options, and label placements.
    • Includes debouncing and two-way data binding.
  • Documentation

    • Added comprehensive examples and guides for textarea usage and features.

Review Change Stack

Move the inner <input> markup behind a protected virtual RenderInputElement
method exposed as a RenderFragment field, mirroring the existing
_renderMainWrapper / _renderInputWrapper / _renderHelperWrapper pattern.
Promote _inputType, InputClass, HasValue, and JSRuntime to protected so
subclasses can override the renderer.

No behavior change for existing inputs (Textbox, Numbox, Datebox).
LumexTextarea<>: multi-line input mirroring LumexTextbox, inheriting from
LumexDebouncedInputBase<string?>. Overrides RenderInputElement to emit
<textarea>; exposes MinRows (3), MaxRows (8), and DisableAutosize.

Companion JS module textarea.js handles HeroUI-style autosize: clamps
height between minRows and maxRows line-heights on input, toggles
data-has-multiple-rows.

Multi-line slot tweaks (h-auto wrapper, resize-none input, top-right
clear button, etc.) live in InputField.GetMultilineStyles, gated on
input is LumexTextarea so LumexNumbox / LumexDatebox stay untouched and
gain no "multiline" concept.
19 facts mirroring TextboxTests structure: <textarea> element rendering,
slot wiring, clear button, focus behavior, OnInput vs OnChange, debounce
delay, and rows attribute matching MinRows. Stubs both input.js and
textarea.js modules.
Top-level Textarea.razor with 16 examples mirroring Textbox plus a new
Autosize section demonstrating MinRows/MaxRows/DisableAutosize. Registers
LumexTextarea in the sidebar (with PageStatus.New) and API navigation, and
adds an entry to llms.txt.
Rendering @CurrentValueAsString as textarea content only sets the
default value (per HTML spec); once the user types, subsequent
re-renders don't sync back to the DOM. Switch to value="@x" attribute,
matching Microsoft's official InputTextArea, so Blazor's renderer
pushes value updates to the textarea's .value DOM property.
The inherited LumexInputFieldBase layout puts clear-button inside
inner-wrapper and wraps everything in main-wrapper when the label is
outside. HeroUI's textarea is flatter: clear-button is a sibling of
inner-wrapper, the outside label sits as a sibling of input-wrapper, and
there is no main-wrapper. Mirror that exactly so the rendered DOM matches
HeroUI's textarea component.

LumexTextarea now renders its own complete tree (no longer routes through
the base's _renderInputElement hook). Textbox / Numbox / Datebox still
inherit the existing base layout and are unaffected.

Promotes LabelClass, InputWrapperClass, InnerWrapperClass, ClearButtonClass,
HelperWrapperClass, DescriptionClass, ErrorMessageClass, ClearButtonVisible,
HasHelper, FocusInputAsync, and ClearAsync to protected so subclasses with
custom rendering can reuse the existing class composition and event handlers.
The hook was added so LumexTextarea could swap the inner element through
the base wrapper, but textarea now renders its own complete DOM, leaving
the hook without overrides. Inline the <input> back into RenderInputWrapper
to keep the base lean.

InputClass / HasValue / JSRuntime stay protected because LumexTextarea's
custom render reuses them.
HeroUI's input.ts defines four `isMultiline`-aware compound variants
that depend on labelPlacement (py-2 on inputWrapper, pb-1.5 / pb-0.5 on
label, pt-0 on input). Apply them in GetMultilineStyles so the rendered
classes match HeroUI's textarea for both inside and outside labels.
…line

HeroUI's `labelPlacement: "outside"` absolute-positioning bundle for the
label and the `has-[label]:mt-X` baseline on the base wrapper are scoped to
the `isMultiline: false` compound. Lumex applied both unconditionally for
outside-label inputs, so textarea + outside label ended up with conflicting
`relative` (from multiline) and `top-1/2 -translate-y-1/2` (from outside)
classes, plus extra top-margin sized for a floating label.

Gate `GetLabelPlacementOutsideBySizeStyles(_, _base|_label)` and the
outside-label branch of `GetLabelPlacementStyles(_, _label)` on
`input is not LumexTextarea` so the label flows naturally above the
textarea with just `relative` + `pb-1.5` (multiline) styling.
…de label

The inside-label scale-down (`group-data-[filled-focused=true]:scale-[0.85]`)
and the size-based translate-up (`group-data-[filled-focused=true]:-translate-y-[calc(...)]`)
are designed for an absolutely-positioned floating label. Textarea forces the
label to `relative` (HeroUI's isMultiline base rule), so those effects shrink
and shift a flow-positioned element in place — the wrong behavior.

Gate the placement-driven `_label` styling on `input is not LumexTextarea`
and move `cursor-text` into GetMultilineStyles so inside-textarea retains the
click-to-focus cursor without the floating-label transitions.
Reverting the scale suppression from the previous commit. The inside-label
`scale-[0.85]` on focus/fill is a desired animation — it works for a
`relative`-positioned textarea label, shrinking in place. Only the size-based
translate-up stays suppressed (that one shifts a flow-positioned element to
nowhere useful).
Now that GetMultilineStyles applies `items-start` to inner-wrapper, the
manual top-margin on icons isn't needed — the flex container aligns
start-content / end-content to the top naturally.
Add the existing `scrollbar-hide` utility to the multiline input slot so the
scrollbar stays out of sight even when content overflows past MaxRows. The
JS autosize logic still sets overflow:auto at the row limit, so wheel /
keyboard scrolling continues to work — only the visual scrollbar is hidden.
Earlier I gated GetLabelPlacementInsideBySizeStyles / OutsideBySizeStyles
entirely off for textarea labels to skip the floating-label translate. That
also dropped the per-size `text-X` rule, so Size.Large textareas (and the
other sizes too) rendered the label at the base `text-small` instead of the
size-appropriate text size.

Un-gate the size helpers for the `_label` slot and instead neutralise just
the parts that conflict with a `relative` flow label in GetMultilineStyles:
`group-data-[filled-focused=true]:translate-y-0` resets the focus-translate,
`left-auto` resets the outside-by-size `left-X` offset. Text size now comes
from the size helper for both inside and outside placements.
Lost in an earlier `git reset --hard` that reverted the data-autosize-disabled
commit and also discarded an uncommitted local edit on the file. Restoring
to the intended baseline.
Render `data-autosize-disabled` on the textarea element reflecting the
DisableAutosize parameter. Gate both `resize-none` and the height transition
on `data-[autosize-disabled=false]` so:

  - With autosize on: JS controls height, `resize-none` blocks the native
    resize handle, and `transition-[height] duration-100` smooths the
    JS-driven grow/shrink.
  - With autosize off: native resize handle is available and there's no
    transition fighting the drag — the lag was the transition catching
    every drag frame.

textarea.js: when disableAutosize is set, skip the input listener and the
adjust() call entirely so user-initiated resizes aren't clobbered on the
next keystroke. The `rows` attribute still provides the initial height.
Keep `resize-none` unconditional and gate only the height transition on
`data-[autosize-disabled=false]`. With DisableAutosize the textarea is
locked at MinRows — no JS-driven autogrow, no native resize handle, no
transition. The transition gating still keeps drag-lag away in case any
height change does happen.
Autosize: put the three demos on a single flex row (default / custom range /
autosize disabled) instead of stacking the disabled one separately.
StartEndContent: make the outer grid `w-full` so it stretches across the
preview container.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4207cf24-9e4b-4074-868e-4d1e0a993ded

📥 Commits

Reviewing files that changed from the base of the PR and between 8c8ec3a and 406581c.

📒 Files selected for processing (2)
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Textarea.razor
  • docs/LumexUI.Docs/wwwroot/llms.txt

📝 Walkthrough

Walkthrough

Adds a new LumexTextarea component (multiline, autosize, debounce), JS autosize controller, styling adjustments for multiline inputs, base-class visibility changes to support inheritance, docs/examples/previews, navigation updates, and comprehensive tests.

Changes

LumexTextarea Component

Layer / File(s) Summary
Base class infrastructure for textarea inheritance
src/LumexUI/Components/Bases/LumexInputFieldBase.razor.cs, src/LumexUI/Components/Bases/InputFieldSlots.cs
Expose JSRuntime, style/class helpers, and input helper methods as protected; update InputFieldSlots docs to include LumexTextarea.
InputField styling system updates for multiline
src/LumexUI/Styles/InputField.cs
Add GetMultilineStyles and integrate textarea-specific style tweaks (label placement, resize/scroll handling, clear-button positioning), adjust label transforms and outside-label spacing gating.
LumexTextarea Razor component and code-behind
src/LumexUI/Components/Textarea/LumexTextarea.razor, src/LumexUI/Components/Textarea/LumexTextarea.razor.cs
New LumexTextarea component inheriting LumexDebouncedInputBase<string?> with MinRows, MaxRows, DisableAutosize; renders label/textarea/clear/helper areas; manages JS module import/init/update/destroy and option-change detection; safe disposal handling.
JavaScript textarea autosize controller
src/LumexUI/wwwroot/js/components/textarea.js
Adds an autosize controller exporting initialize, update, and destroy that measures typography/box metrics, computes min/max heights from row counts, and adjusts height on input when enabled.
Documentation examples and preview wrappers
docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/*, docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/*, docs/LumexUI.Docs.Client/Pages/Components/Textarea/Textarea.razor, docs/LumexUI.Docs.Client/Common/Navigation/NavigationStore.cs, docs/LumexUI.Docs/wwwroot/llms.txt
Add ~17 example pages demonstrating features (autosize, clear button, colors, custom styles, debounce, description, disabled, error message with FluentValidation, label placements, readonly, required, sizes, start/end content, two-way binding, usage, variants, radius), preview wrappers for interactive rendering, main docs page, navigation entries and llms index update.
Test suite
tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor
Add comprehensive tests covering rendering, attributes, label/helper/error display, disabled/rows behavior, clear-button click/keyboard, focus behavior, input vs change event flows, debounced updates, and invalid option validation.

Sequence Diagram

sequenceDiagram
  participant LumexTextarea as LumexTextarea (Render)
  participant IJSModule as IJSRuntime (module)
  participant TextareaJS as textarea.js

  LumexTextarea->>IJSModule: import module (OnAfterRenderAsync)
  IJSModule->>TextareaJS: initialize(element, options)
  TextareaJS->>TextareaJS: adjust height, register input listener
  LumexTextarea->>IJSModule: update(element, options) (when MinRows/MaxRows/DisableAutosize change)
  IJSModule->>TextareaJS: update(element, options)
  LumexTextarea->>IJSModule: DisposeAsync -> destroy(element)
  IJSModule->>TextareaJS: destroy(element)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • LumexUI/lumexui#121: Adds component navigation entries similar to this PR.
  • LumexUI/lumexui#94: Related input infrastructure changes used by textarea (base input patterns and styles).
  • LumexUI/lumexui#272: Edits to docs index/navigation (llms.txt) related to component documentation.

Suggested labels

📦 Scope: Components, 🚀 Type: Feature

Poem

A textarea blooms in the UI so bright, 🐰
Rows stretch and shrink to fit just right,
Debounce hums soft, JS trims the height,
Examples and tests keep behavior tight.
Little rabbit hops—docs gleam in the light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(components): add Textarea component' directly and clearly describes the main change: adding a new Textarea component to the LumexUI library.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering the feature scope, implementation details, testing, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/textarea

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 74.13793% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.71%. Comparing base (19b89dc) to head (406581c).
⚠️ Report is 183 commits behind head on main.

Files with missing lines Patch % Lines
...LumexUI/Components/Textarea/LumexTextarea.razor.cs 65.71% 10 Missing and 2 partials ⚠️
...rc/LumexUI/Components/Textarea/LumexTextarea.razor 85.00% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #313      +/-   ##
==========================================
- Coverage   96.95%   92.71%   -4.24%     
==========================================
  Files          70      168      +98     
  Lines        1542     2811    +1269     
  Branches      150      416     +266     
==========================================
+ Hits         1495     2606    +1111     
- Misses         28      109      +81     
- Partials       19       96      +77     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (3)
tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor (1)

90-98: ⚡ Quick win

Consider adding test coverage for MaxRows and DisableAutosize parameters.

The tests verify MinRows maps to the rows attribute, but the PR objectives describe MaxRows and DisableAutosize as key parameters. Adding tests for these would improve coverage:

  1. A test verifying that MaxRows is accepted (it may not directly affect DOM since autosize constraints are JS-side, but you could verify the component renders without throwing).
  2. A test verifying that DisableAutosize="true" sets the data-autosize-disabled attribute (mentioned in PR objectives).
📝 Example test stubs
[Fact]
public void ShouldAcceptMaxRowsParameter()
{
    var action = () => Render(@<LumexTextarea Label="Test" MinRows="3" MaxRows="10" />);
    
    action.Should().NotThrow();
}

[Fact]
public void ShouldSetDataAutosizeDisabledWhenDisableAutosizeTrue()
{
    var cut = Render(@<LumexTextarea Label="Test" DisableAutosize="true" />);
    
    var textarea = cut.Find( "textarea" );
    textarea.GetAttribute( "data-autosize-disabled" ).Should().Be( "true" );
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor` around lines 90
- 98, Add two tests to TextareaTests.razor: one that renders LumexTextarea with
MaxRows set (e.g., Render(@<LumexTextarea Label="Test" MinRows="3" MaxRows="10"
/>)) and asserts that rendering does not throw (use an Action and
Should().NotThrow()), and another that renders LumexTextarea with
DisableAutosize="true", finds the "textarea" element and asserts its
data-autosize-disabled attribute equals "true"; reference the existing
ShouldHaveRowsAttributeMatchingMinRows test for style and use the same Render
and cut.Find("textarea") patterns.
docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/_Radius.razor (1)

5-5: 💤 Low value

Consider using variant-specific labels for clarity.

All textareas share the same hardcoded Label="Radius", making it difficult to distinguish between variants at a glance. Consider using the radius value in the label (e.g., Label="@($"Radius: {radius}")) to improve visual differentiation in the documentation.

📝 Suggested improvement
-            <LumexTextarea Radius="@radius" Label="Radius" Placeholder="@radius.ToString()" />
+            <LumexTextarea Radius="@radius" Label="@($"Radius: {radius}")" Placeholder="Enter text here..." />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/_Radius.razor` at
line 5, The Label for the example LumexTextarea is hardcoded as "Radius", making
variants indistinguishable; update the LumexTextarea usage (the component
instance using the Radius parameter and Label attribute) to interpolate the
radius value into the label (e.g., use string interpolation to set Label to
include the radius value) so each variant shows a distinct label like "Radius:
{radius}".
src/LumexUI/Components/Textarea/LumexTextarea.razor.cs (1)

23-31: ⚡ Quick win

Consider validating MinRows ≤ MaxRows.

The component allows MinRows and MaxRows to be set independently without validation. If MaxRows < MinRows, the JS autosize logic will compute Math.max(contentHeight, minHeight) followed by Math.min(..., maxHeight), which could clamp the textarea to MaxRows even when content is less than MinRows, producing unexpected behavior.

🛡️ Suggested validation in SetParametersAsync or OnParametersSet
+/// <inheritdoc />
+protected override void OnParametersSet()
+{
+    base.OnParametersSet();
+    
+    if( MaxRows < MinRows )
+    {
+        throw new ArgumentException( $"{nameof(MaxRows)} ({MaxRows}) must be greater than or equal to {nameof(MinRows)} ({MinRows})." );
+    }
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/LumexUI/Components/Textarea/LumexTextarea.razor.cs` around lines 23 - 31,
Validate that MinRows is not greater than MaxRows in the LumexTextarea component
(LumexTextarea.razor.cs) by adding a check in SetParametersAsync or
OnParametersSet: if MinRows > MaxRows, either swap them or clamp MinRows to
MaxRows (or throw/Log an ArgumentException) and ensure any computed
minHeight/maxHeight logic uses the corrected values; reference the MinRows and
MaxRows properties and the SetParametersAsync/OnParametersSet lifecycle methods
to locate where to perform this validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/ErrorMessage.razor`:
- Around line 24-27: The OnBioChange handler in the Textarea example currently
declares a non-nullable parameter (string) but must accept a nullable string to
match LumexTextarea's ValueChanged contract (LumexDebouncedInputBase<string?>);
change the signature of OnBioChange to take string? (nullable) and update any
null-safe assignments inside (e.g., assign _user.Bio = value ?? string.Empty or
handle null appropriately) so the handler aligns with ValueChanged and avoids
nullable-mismatch warnings.

In
`@docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/TwoWayDataBinding.razor`:
- Around line 28-31: The handler OnValueChanged currently accepts a non-nullable
string but LumexTextarea is used with TValue = string? and its ValueChanged is
EventCallback<string?>; update the OnValueChanged signature to accept string?
(nullable) so it matches the EventCallback<string?>, and ensure any assignment
to _valueTwo accepts null (e.g., _valueTwo = value) without forcing non-null;
reference the OnValueChanged method, the _valueTwo field, and the LumexTextarea
TValue/ValueChanged types when making the change.

In `@docs/LumexUI.Docs.Client/Pages/Components/Textarea/Textarea.razor`:
- Line 180: The docs mistakenly list InputFieldSlots.MainWrapper for
LumexTextarea even though LumexTextarea does not render a main-wrapper; remove
the entry new(nameof(InputFieldSlots.MainWrapper), ...) from the Textarea slot
documentation so the slot API accurately reflects LumexTextarea's rendered slots
and only documents the actual slots exposed by LumexTextarea.

In `@docs/LumexUI.Docs/wwwroot/llms.txt`:
- Around line 9-13: The Key Features list contains mojibake characters ("�") in
the bullet lines; open the Key Features text block in llms.txt (the list entries
starting with "Tailwind CSS�based" etc.) and replace each corrupted character
with the correct punctuation/spacing (e.g., change "Tailwind CSS�based" to
"Tailwind CSS-based", "Clean by default � Professional" to "Clean by default —
Professional" or a normal hyphen/emdash as consistent with other bullets),
ensuring all instances of "�" are removed and proper ASCII/Unicode punctuation
and spacing are used so the bullets read cleanly and indexable.

In `@tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor`:
- Line 15: The JS interop setup uses
inputModule.Setup<string>("input.getValidationMessage", _ => true) but the
lambda returns a boolean, causing a type mismatch; fix by either (a) if the
interop should return a string, change the lambda to return the appropriate
message string (e.g., _ => "validation message") and keep Setup<string>, (b) if
it should return a boolean change the setup to
Setup<bool>("input.getValidationMessage", _ => true), or (c) if the return value
is unused adjust the generic to match the actual expectation (e.g.,
Setup<object> or Setup<string> with _ => string.Empty) so the delegate return
type matches the generic used in inputModule.Setup.

---

Nitpick comments:
In `@docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/_Radius.razor`:
- Line 5: The Label for the example LumexTextarea is hardcoded as "Radius",
making variants indistinguishable; update the LumexTextarea usage (the component
instance using the Radius parameter and Label attribute) to interpolate the
radius value into the label (e.g., use string interpolation to set Label to
include the radius value) so each variant shows a distinct label like "Radius:
{radius}".

In `@src/LumexUI/Components/Textarea/LumexTextarea.razor.cs`:
- Around line 23-31: Validate that MinRows is not greater than MaxRows in the
LumexTextarea component (LumexTextarea.razor.cs) by adding a check in
SetParametersAsync or OnParametersSet: if MinRows > MaxRows, either swap them or
clamp MinRows to MaxRows (or throw/Log an ArgumentException) and ensure any
computed minHeight/maxHeight logic uses the corrected values; reference the
MinRows and MaxRows properties and the SetParametersAsync/OnParametersSet
lifecycle methods to locate where to perform this validation.

In `@tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor`:
- Around line 90-98: Add two tests to TextareaTests.razor: one that renders
LumexTextarea with MaxRows set (e.g., Render(@<LumexTextarea Label="Test"
MinRows="3" MaxRows="10" />)) and asserts that rendering does not throw (use an
Action and Should().NotThrow()), and another that renders LumexTextarea with
DisableAutosize="true", finds the "textarea" element and asserts its
data-autosize-disabled attribute equals "true"; reference the existing
ShouldHaveRowsAttributeMatchingMinRows test for style and use the same Render
and cut.Find("textarea") patterns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e33aaada-2168-4f7e-8441-5dabb2e87867

📥 Commits

Reviewing files that changed from the base of the PR and between 8a459b7 and 8c8ec3a.

📒 Files selected for processing (44)
  • docs/LumexUI.Docs.Client/Common/Navigation/NavigationStore.cs
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Autosize.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/ClearButton.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Colors.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/CustomStyles.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/DebounceDelay.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Description.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Disabled.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/ErrorMessage.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/LabelPlacements.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/ReadOnly.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Required.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Sizes.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/StartEndContent.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/TwoWayDataBinding.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Usage.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/Variants.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Examples/_Radius.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Autosize.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/ClearButton.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Colors.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/CustomStyles.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/DebounceDelay.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Description.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Disabled.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/ErrorMessage.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/LabelPlacements.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Radius.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/ReadOnly.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Required.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Sizes.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/StartEndContent.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/TwoWayDataBinding.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Usage.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/PreviewCodes/Variants.razor
  • docs/LumexUI.Docs.Client/Pages/Components/Textarea/Textarea.razor
  • docs/LumexUI.Docs/wwwroot/llms.txt
  • src/LumexUI/Components/Bases/InputFieldSlots.cs
  • src/LumexUI/Components/Bases/LumexInputFieldBase.razor.cs
  • src/LumexUI/Components/Textarea/LumexTextarea.razor
  • src/LumexUI/Components/Textarea/LumexTextarea.razor.cs
  • src/LumexUI/Styles/InputField.cs
  • src/LumexUI/wwwroot/js/components/textarea.js
  • tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor

Comment thread docs/LumexUI.Docs.Client/Pages/Components/Textarea/Textarea.razor Outdated
Comment thread docs/LumexUI.Docs/wwwroot/llms.txt Outdated
Comment thread tests/LumexUI.Tests/Components/Textarea/TextareaTests.razor
@desmondinho desmondinho merged commit 1cb3e3c into main May 14, 2026
1 of 2 checks passed
@desmondinho desmondinho deleted the feat/textarea branch May 14, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add Textarea component

1 participant