Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Component shapes

A component shape connects a form-side value to GPUI state, rendering, and events. Prefer a ready-made collection or component-owned shape. Define an application-owned shape when the existing contracts cannot represent the widget or construction behavior you need.

Choose the package

  • Use gpui-form-collection for common GPUI Kit controls.
  • Use gpui-form-component for localized date and file pickers or cascading infinite selects.
  • Use component-shape-gpui and gpui-form-runtime when a crate defines its own reusable shape.

Applications that only consume existing shapes use the gpui_form::runtime::shape facade and do not need a direct gpui-form-runtime dependency.

Collection shapes

gpui-form-collection provides these form shapes:

NeedShape
A FromStr + ToString + 'static valueinput::Input::<T>
Application-defined text parsing and formattinginput::ParsedInput::<T, Config>
One enum-like valueselect::Select::<T>
Several enum-like valuescombobox::Combobox::<Item>
Boolean valuecheckbox::Checkbox or switch::Switch
Numeric text inputnumber_input::NumberInput::<T>
f32 or gpui_kit::component::slider::SliderValueslider::Slider
gpui_kit::Hslacolor_picker::ColorPicker
chrono::NaiveDate or a date pairdate_picker::DatePicker or DateRangePicker
One-time-password valueotp_input::OtpInput::<T>

ParsedInput<T, Config> uses a ParsedInputConfig<T> implementation for parsing, formatting, placeholder text, empty-as-clear behavior, and optional widget validation.

Select values normally derive SelectItem from gpui-form-collection-derive and EnumIter from strum. The generic parameter of Combobox<Item> is the item type, so a Vec<Country> field uses Combobox::<Country>.

Configure one field

Built-in shapes expose builder expressions inside component(...):

#[gpui_form(component(
    gpui_form_collection::select::Select::<_>.searchable(true)
))]
country: Country,

Use Shape.from(options) when the shape publishes a completed options type. Configuration changes construction for that field while preserving the base shape’s value compatibility, rendering, storage, and metadata.

Component-owned shapes

Enable the form-shape implementations and derives you use:

[dependencies]
gpui-form-component = { version = "0.7", features = ["component-shape", "derive"] }
NeedShapeRequirement
Localized date or date rangegpui_form_component::date_picker::DatePicker or DateRangePickerInitialize application gpui-es-fluent resources
Native file or directory selectiongpui_form_component::file_picker::FilePickerInitialize application gpui-es-fluent resources
Cascading enum choicesgpui_form_component::infinite_select::InfiniteSelect::<T>Derive InfiniteSelect and implement Clone + Default + PartialEq + 'static throughout the enum tree

Nested infinite-select payload types must implement Default. Use InfiniteSelect::<_>.searchable(true) for search or InfiniteSelect::<_>.from(InfiniteSelectOptions::new(true, Some(3))) for search plus a maximum depth.

Define an application-owned shape

Declare an owned rendered component with #[derive(component_shape_gpui::GpuiComponentShape)], or wrap an external state/component pair with component_shape_gpui::component_shape!. Then attach the form storage policy:

impl gpui_form_runtime::shape::GpuiFormComponentShapePolicy for EmailInputShape {
    type ValueStoragePolicy =
        gpui_form_runtime::shape::DirectValueStorage;
}

A reusable shape defines:

  • backing entity state and construction
  • a render component
  • supported value types
  • event-to-value binding when the form should synchronize automatically
  • form holder storage policy
  • a stable prototyping field suffix
  • MCP input metadata when the wire contract needs shape-specific guidance

A shape declared only through a hand-written GpuiComponentShape implementation lacks the declaration marker required by GpuiForm. Use the derive or macro so the generated contract includes that marker and its metadata.

Storage policy

DirectValueStorage stores T for a non-optional field. Initialization comes from an intent-scoped default or the form-side type’s Default implementation.

RequiredValueStorage stores Option<T> so the form can represent missing input. Holder conversion reports an absent required value. Generated validation reports the same condition when Koruma integration is enabled.

Troubleshooting

SymptomAction
A component-owned type cannot be used in component(...)Enable gpui-form-component’s component-shape feature.
The derive rejects an application-owned shape as undeclaredDeclare it with the GpuiComponentShape derive or component_shape! macro.
A configured shape expression fails its boundUse a builder produced for the same base shape, or pass its completed options through Shape.from(...).
Prototyping reports missing capabilitiesAdd the missing render, value-binding, shape-path, or storage metadata to the owning shape and regenerate.