Skip to content

Conversation

@sxhxliang
Copy link

@sxhxliang sxhxliang commented Nov 24, 2025

  • Introduce InputGroup component with flexible layout and alignment options
  • Add supporting components: InputGroupAddon, InputGroupText, InputGroupInput, and InputGroupTextarea
  • Implement various examples including search, URL input, validation, and chat interfaces
  • Update story module to include and initialize InputGroupStory
  • Register InputGroup in the main UI module exports

Description

Add a new shadcn/ui InputGroup component that provides a flexible way to compose input fields with addons such as icons, buttons, and text labels.

Features:

  • InputGroup: Main container with support for disabled/invalid states, horizontal/vertical layouts
  • InputGroupAddon: Flexible addon container with alignment options (InlineStart, InlineEnd, BlockStart,
    BlockEnd)
  • InputGroupText: Simple text element for labels within addons
  • InputGroupInput: Styled input wrapper that integrates seamlessly with the group
  • InputGroupTextarea: Multi-line text input variant for chat-like interfaces

Examples included:

  • Basic search with icon and results count
  • URL input with protocol prefix
  • Username with validation badge
  • Search with clear button and loading state
  • Chat input with bottom toolbar

Screenshot

Before After
Windows/- image
macOS/- image

Break Changes

Describe any breaking changes introduced by this pull request. If none, remove this section.

  • Change 1

None

How to Test

  1. Run the story application:
    cargo run
  2. Navigate to the InputGroup story panel
  3. Verify the following examples render correctly:
    - Basic Search with Icon and Results
    - URL Input with Protocol Prefix
    - Username with Validation Icon
    - Search with Clear Button
    - Search with Loading State
    - Multiple Icons
    - With Action Button
    - Disabled State
    - Invalid/Error State
    - Chat Input with Toolbar

Checklist

  • I have read the CONTRIBUTING document and followed the guidelines.
  • Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate.
  • Passed cargo run for story tests related to the changes.
  • Tested macOS, Windows platforms performance (if the change is platform-specific)

…dons

- Introduce `InputGroup` component with flexible layout and alignment options
- Add supporting components: `InputGroupAddon`, `InputGroupText`,
  `InputGroupInput`, and `InputGroupTextarea`
- Implement various examples including search, URL input, validation,
  and chat interfaces
- Update story module to include and initialize InputGroupStory
- Register InputGroup in the main UI module exports
@sxhxliang sxhxliang marked this pull request as ready for review November 24, 2025 13:01
@huacnlee huacnlee changed the title feat(ui): add InputGroup component for composing input fields with ad… input_group: Add InputGroup component. Nov 24, 2025
/// Create a standard InputGroup with max-width
fn example_group() -> InputGroup {
InputGroup::new().max_w_96()
}
Copy link
Member

@huacnlee huacnlee Nov 24, 2025

Choose a reason for hiding this comment

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

As the example, we should keep the example simple and clean to understand.

Move these things to render method to as a nested layout, even it will duplicate code.

const DEFAULT_ADDON_PADDING: Pixels = px(12.);
const DEFAULT_TEXTAREA_HEIGHT: Pixels = px(80.);

// === Types ===
Copy link
Member

Choose a reason for hiding this comment

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

Remove all comments like this.


// === Constants ===

const DEFAULT_INPUT_GROUP_ID: &str = "input-group";
Copy link
Member

Choose a reason for hiding this comment

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

Remove this, and use InputGroup as the group id.

/// Marks the input group as invalid/error state.
///
/// When `true`, the border color changes to indicate an error.
pub fn invalid(mut self, invalid: bool) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

I think, we are not ready to introduce this feature, because danger not enough. So this API we need to consider more before add.

Please remove it, with replacement, user can be based on style for adding the invalid style.

fn default() -> Self {
Self::new()
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Remove default for InputGroup, just use new method.

let border = self.get_border_color(cx);

div()
.id(self.id.unwrap_or_else(|| DEFAULT_INPUT_GROUP_ID.into()))
Copy link
Member

Choose a reason for hiding this comment

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

If the id is not required, just removed it. Here, this code is not correct.

div()
.id(self.id.unwrap_or_else(|| DEFAULT_INPUT_GROUP_ID.into()))
.w_full()
.min_w_0()
Copy link
Member

Choose a reason for hiding this comment

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

Why need this? So, please review you self agian.

.when(cx.theme().shadow, |this| this.shadow_xs())
.when(self.disabled, |this| {
this.opacity(0.5).cursor_not_allowed()
})
Copy link
Member

Choose a reason for hiding this comment

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

Disabled style should not just change the opacity, please follow disabled style of the Input, Button.

pub fn align(mut self, align: InputGroupAlign) -> Self {
self.align = align;
self
}
Copy link
Member

Choose a reason for hiding this comment

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

We also need add helper methods like inline_end, inline_start, block_start and block_end, and please order the method by name.

.text_sm()
.font_medium()
.cursor_text()
.pl(padding.0)
Copy link
Member

Choose a reason for hiding this comment

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

Use p(padding) instead.

/// Creates a text label with default styling.
///
/// This is a convenience method for quickly creating text elements.
pub fn label(text: impl Into<String>) -> impl IntoElement {
Copy link
Member

Choose a reason for hiding this comment

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

Use Into<SharedShared>

Copy link
Member

Choose a reason for hiding this comment

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

And why have this method? This is not for InputGroupText.

/// ```
#[derive(IntoElement)]
pub struct InputGroupInput {
state: gpui::Entity<crate::input::InputState>,
Copy link
Member

Choose a reason for hiding this comment

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

Clean code, use Entity and InputState.

pub fn height(mut self, height: impl Into<Option<DefiniteLength>>) -> Self {
self.height = height.into();
self
}
Copy link
Member

Choose a reason for hiding this comment

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

Remove this method, use style instead, so user can use h method.

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.

2 participants