@vtex/faststore 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/dist/actions.json +181 -0
- package/dist/catalog.json +1595 -481
- package/dist/client.d.ts +2 -1
- package/dist/client.js +2 -1
- package/dist/components.d.ts +31 -7
- package/dist/components.js +35 -13
- package/dist/content-types.json +73 -0
- package/dist/docs/access-code-sign-in.md +1 -1
- package/dist/docs/account-access-gate.md +153 -0
- package/dist/docs/account-entry-point.md +1 -2
- package/dist/docs/account-menu.md +164 -0
- package/dist/docs/address-summary.md +24 -3
- package/dist/docs/alert-dialog.md +204 -0
- package/dist/docs/billing-address.md +284 -0
- package/dist/docs/buy-button.md +1 -1
- package/dist/docs/card-entry.md +250 -0
- package/dist/docs/cardholder-document.md +142 -0
- package/dist/docs/cart.md +1 -1
- package/dist/docs/client-preferences-fieldset.md +148 -0
- package/dist/docs/client-preferences.md +2 -1
- package/dist/docs/client-profile-fieldset.md +184 -0
- package/dist/docs/client-profile.md +1 -1
- package/dist/docs/document-field.md +58 -4
- package/dist/docs/field.md +317 -0
- package/dist/docs/form.md +307 -0
- package/dist/docs/identity-edit.md +6 -6
- package/dist/docs/identity-summary.md +5 -5
- package/dist/docs/installments.md +248 -0
- package/dist/docs/my-account-profile.md +1 -0
- package/dist/docs/order-placed-payment-summary.md +138 -0
- package/dist/docs/payment-method-badges.md +232 -0
- package/dist/docs/payment-methods.md +1 -0
- package/dist/docs/payment.md +218 -0
- package/dist/docs/phone-field.md +58 -4
- package/dist/docs/place-order.md +157 -0
- package/dist/docs/save-card.md +186 -0
- package/dist/docs/saved-cards.md +218 -0
- package/dist/docs/select.md +465 -0
- package/dist/docs/session.md +1 -1
- package/dist/docs/shipping-address.md +110 -258
- package/dist/docs/sign-in-redirect.md +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/internal/client.d.ts +3 -1
- package/dist/internal/client.js +3 -1
- package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
- package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
- package/dist/matter/account-access-gate/account-access-gate.d.ts +86 -0
- package/dist/matter/account-access-gate/account-access-gate.js +283 -0
- package/dist/matter/account-access-gate/account-access-gate.js.map +1 -0
- package/dist/matter/account-access-gate/sign-out-intent.d.ts +17 -0
- package/dist/matter/account-access-gate/sign-out-intent.js +62 -0
- package/dist/matter/account-access-gate/sign-out-intent.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.js +2 -2
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +88 -0
- package/dist/matter/account-menu/account-menu.js +246 -0
- package/dist/matter/account-menu/account-menu.js.map +1 -0
- package/dist/matter/billing-address/billing-address.d.ts +165 -0
- package/dist/matter/billing-address/billing-address.js +408 -0
- package/dist/matter/billing-address/billing-address.js.map +1 -0
- package/dist/matter/card-entry/card-capture.d.ts +25 -0
- package/dist/matter/card-entry/card-capture.js +25 -0
- package/dist/matter/card-entry/card-capture.js.map +1 -0
- package/dist/matter/card-entry/card-entry.d.ts +120 -0
- package/dist/matter/card-entry/card-entry.js +832 -0
- package/dist/matter/card-entry/card-entry.js.map +1 -0
- package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
- package/dist/matter/cardholder-document/cardholder-document.js +70 -0
- package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
- package/dist/matter/cart/cart.d.ts +1 -1
- package/dist/matter/cart/cart.js +2 -2
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
- package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
- package/dist/matter/client-preferences/client-preferences.js +6 -6
- package/dist/matter/client-preferences/client-preferences.js.map +1 -1
- package/dist/matter/client-profile/client-profile.d.ts +4 -6
- package/dist/matter/client-profile/client-profile.js +9 -6
- package/dist/matter/client-profile/client-profile.js.map +1 -1
- package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
- package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
- package/dist/matter/delivery-options/delivery-options.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.js +2 -2
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.js +2 -2
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/installments/installments-select.d.ts +42 -0
- package/dist/matter/installments/installments-select.js +167 -0
- package/dist/matter/installments/installments-select.js.map +1 -0
- package/dist/matter/installments/installments.d.ts +58 -0
- package/dist/matter/installments/installments.js +176 -0
- package/dist/matter/installments/installments.js.map +1 -0
- package/dist/matter/installments/use-installments-selection.d.ts +29 -0
- package/dist/matter/installments/use-installments-selection.js +95 -0
- package/dist/matter/installments/use-installments-selection.js.map +1 -0
- package/dist/matter/my-account-profile/my-account-profile.js +5 -5
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.d.ts +19 -0
- package/dist/matter/payment/payment-card-capture.js +129 -0
- package/dist/matter/payment/payment-card-capture.js.map +1 -0
- package/dist/matter/payment/payment-controller.d.ts +24 -0
- package/dist/matter/payment/payment-controller.js +107 -0
- package/dist/matter/payment/payment-controller.js.map +1 -0
- package/dist/matter/payment/payment-method-badges.d.ts +57 -0
- package/dist/matter/payment/payment-method-badges.js +192 -0
- package/dist/matter/payment/payment-method-badges.js.map +1 -0
- package/dist/matter/payment/payment.d.ts +89 -0
- package/dist/matter/payment/payment.js +263 -0
- package/dist/matter/payment/payment.js.map +1 -0
- package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
- package/dist/matter/payment/use-payment-method-selection.js +458 -0
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
- package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
- package/dist/matter/payment/use-payment-submit-gate.js +144 -0
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
- package/dist/matter/place-order/place-order.d.ts +74 -0
- package/dist/matter/place-order/place-order.js +379 -0
- package/dist/matter/place-order/place-order.js.map +1 -0
- package/dist/matter/product-list/product-list.d.ts +1 -0
- package/dist/matter/product-list/product-list.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
- package/dist/matter/product-shelf/product-shelf.js +2 -0
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.js +1 -1
- package/dist/matter/region/region.js.map +1 -1
- package/dist/matter/save-card/save-card.d.ts +49 -0
- package/dist/matter/save-card/save-card.js +188 -0
- package/dist/matter/save-card/save-card.js.map +1 -0
- package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
- package/dist/matter/saved-cards/saved-cards.js +387 -0
- package/dist/matter/saved-cards/saved-cards.js.map +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +20 -10
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
- package/dist/matter/shipping-address/shipping-address.js +481 -792
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/variant-selector/variant-selector.js +1 -1
- package/dist/particles/address-summary/address-summary.d.ts +24 -0
- package/dist/particles/address-summary/address-summary.js +83 -2
- package/dist/particles/address-summary/address-summary.js.map +1 -1
- package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
- package/dist/particles/alert-dialog/alert-dialog.js +187 -0
- package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
- package/dist/particles/checkbox/checkbox.d.ts +7 -3
- package/dist/particles/checkbox/checkbox.js +4 -1
- package/dist/particles/checkbox/checkbox.js.map +1 -1
- package/dist/particles/document-field/document-field.d.ts +48 -5
- package/dist/particles/document-field/document-field.js +189 -32
- package/dist/particles/document-field/document-field.js.map +1 -1
- package/dist/particles/field/bound-field-registry.js +52 -0
- package/dist/particles/field/bound-field-registry.js.map +1 -0
- package/dist/particles/field/field.d.ts +116 -0
- package/dist/particles/field/field.js +497 -6
- package/dist/particles/field/field.js.map +1 -1
- package/dist/particles/fieldset/fieldset.js +2 -2
- package/dist/particles/fieldset/fieldset.js.map +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/form/form.d.ts +104 -0
- package/dist/particles/form/form.js +485 -0
- package/dist/particles/form/form.js.map +1 -0
- package/dist/particles/incentives/incentives.js +1 -1
- package/dist/particles/phone-field/phone-field.d.ts +38 -10
- package/dist/particles/phone-field/phone-field.js +183 -39
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/postal-code-field/postal-code-field.js +2 -2
- package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
- package/dist/particles/select/field-select.d.ts +43 -0
- package/dist/particles/select/field-select.js +150 -0
- package/dist/particles/select/field-select.js.map +1 -0
- package/dist/particles/select/select.d.ts +2 -0
- package/dist/particles/select/select.js.map +1 -1
- package/dist/particles/shared/compose-refs.js +21 -0
- package/dist/particles/shared/compose-refs.js.map +1 -0
- package/dist/schema.graphql +701 -2
- package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
- package/dist/sdk/actions/analytics-action-provider.js +19 -0
- package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
- package/dist/sdk/actions/cart-action-provider.d.ts +1 -1
- package/dist/sdk/actions/cart-action-provider.js +1 -1
- package/dist/sdk/actions/cart-action-provider.js.map +1 -1
- package/dist/sdk/actions/index.d.ts +3 -1
- package/dist/sdk/actions/index.js +3 -1
- package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
- package/dist/sdk/actions/payment-action-provider.js +26 -0
- package/dist/sdk/actions/payment-action-provider.js.map +1 -0
- package/dist/sdk/actions/session-action-provider.d.ts +1 -1
- package/dist/sdk/actions/session-action-provider.js +1 -1
- package/dist/sdk/actions/session-action-provider.js.map +1 -1
- package/dist/sdk/actions/shipping-action-provider.d.ts +1 -1
- package/dist/sdk/actions/shipping-action-provider.js +1 -1
- package/dist/sdk/actions/shipping-action-provider.js.map +1 -1
- package/dist/sdk/actions/types.d.ts +6 -2
- package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
- package/dist/sdk/analytics/analytics-destination.js +90 -0
- package/dist/sdk/analytics/analytics-destination.js.map +1 -0
- package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
- package/dist/sdk/analytics/use-analytics-actions.js +108 -0
- package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
- package/dist/sdk/cache/storefront-cache.js +1 -1
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +4 -4
- package/dist/sdk/cart/operations.js +1 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.js +1 -1
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +1 -1
- package/dist/sdk/cart/use-cart-actions.js +4 -4
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
- package/dist/sdk/cart/write-gate.js +1 -1
- package/dist/sdk/cart/write-gate.js.map +1 -1
- package/dist/sdk/data/entity-resolution-context.js +31 -0
- package/dist/sdk/data/entity-resolution-context.js.map +1 -0
- package/dist/sdk/data/entity-subscriber.js +18 -8
- package/dist/sdk/data/entity-subscriber.js.map +1 -1
- package/dist/sdk/data/index.js +1 -0
- package/dist/sdk/data/page-reactive-data-root.d.ts +38 -2
- package/dist/sdk/data/page-reactive-data-root.js +4 -2
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
- package/dist/sdk/data/reactive-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-data-provider.js +8 -4
- package/dist/sdk/data/reactive-data-provider.js.map +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.js +13 -5
- package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
- package/dist/sdk/data/use-reactive-data-settled.js +39 -0
- package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
- package/dist/sdk/data/use-reactive-entity.js +6 -2
- package/dist/sdk/data/use-reactive-entity.js.map +1 -1
- package/dist/sdk/generated/fragment-types.js +2 -0
- package/dist/sdk/generated/fragment-types.js.map +1 -1
- package/dist/sdk/generated/gql.js +2 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.js +85 -1
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/messages/en-US.js +3 -0
- package/dist/sdk/i18n/messages/en-US.json +3 -0
- package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
- package/dist/sdk/i18n/messages/es-ES.js +3 -0
- package/dist/sdk/i18n/messages/es-ES.json +3 -0
- package/dist/sdk/i18n/messages/pt-BR.js +3 -0
- package/dist/sdk/i18n/messages/pt-BR.json +3 -0
- package/dist/sdk/identity/operations.js.map +1 -1
- package/dist/sdk/identity/use-identity-actions.d.ts +1 -1
- package/dist/sdk/identity/use-identity-actions.js +3 -2
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/payment/gateway-origin.js +35 -0
- package/dist/sdk/payment/gateway-origin.js.map +1 -0
- package/dist/sdk/payment/gateway.d.ts +85 -0
- package/dist/sdk/payment/gateway.js +183 -0
- package/dist/sdk/payment/gateway.js.map +1 -0
- package/dist/sdk/payment/operations.d.ts +52 -0
- package/dist/sdk/payment/operations.js +223 -0
- package/dist/sdk/payment/operations.js.map +1 -0
- package/dist/sdk/payment/security-code-mask.js +71 -0
- package/dist/sdk/payment/security-code-mask.js.map +1 -0
- package/dist/sdk/payment/submission-registry.d.ts +33 -0
- package/dist/sdk/payment/submission-registry.js +58 -0
- package/dist/sdk/payment/submission-registry.js.map +1 -0
- package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
- package/dist/sdk/payment/use-payment-actions.js +276 -0
- package/dist/sdk/payment/use-payment-actions.js.map +1 -0
- package/dist/sdk/payment/use-place-order.d.ts +65 -0
- package/dist/sdk/payment/use-place-order.js +640 -0
- package/dist/sdk/payment/use-place-order.js.map +1 -0
- package/dist/sdk/session/auth-operations.d.ts +1 -1
- package/dist/sdk/session/auth-operations.js.map +1 -1
- package/dist/sdk/session/use-session-actions.d.ts +1 -1
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/session/use-session-revalidation.js +65 -0
- package/dist/sdk/session/use-session-revalidation.js.map +1 -0
- package/dist/sdk/shipping/option-select-operations.d.ts +1 -1
- package/dist/sdk/shipping/option-select-operations.js.map +1 -1
- package/dist/sdk/shipping/request-timeout.js +1 -1
- package/dist/sdk/shipping/request-timeout.js.map +1 -1
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.d.ts +2 -2
- package/dist/sdk/shipping/use-shipping-actions.js +1 -1
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +3 -4
- package/dist/sdk/state/cart.js +6 -7
- package/dist/sdk/state/cart.js.map +1 -1
- package/dist/utils/loggable-error-name.js +49 -0
- package/dist/utils/loggable-error-name.js.map +1 -0
- package/dist/utils/resolve-authored-copy.js +18 -0
- package/dist/utils/resolve-authored-copy.js.map +1 -0
- package/dist/utils/safe-href.js +3 -3
- package/dist/utils/safe-href.js.map +1 -1
- package/dist/utils/substitute-template.js +33 -0
- package/dist/utils/substitute-template.js.map +1 -0
- package/package.json +2 -1
- package/src/styles/tailwind.css +34 -0
- package/dist/docs/client-profile-form.md +0 -192
- package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
- package/dist/matter/client-profile-form/client-profile-form.js +0 -662
- package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
# Select
|
|
2
|
+
|
|
3
|
+
**Category:** layout
|
|
4
|
+
**Purpose:** Composable dropdown-select anatomy — nineteen generic `Select.*` parts wrapping Base UI's
|
|
5
|
+
`Select`, plus four `FieldSelect.*` parts that bind a chosen-option field to react-hook-form through the
|
|
6
|
+
field contract (`FieldBinding`/`useField`, see [[field]]).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Visual cues (how to identify in an image)
|
|
11
|
+
|
|
12
|
+
A Select block is a **single-choice dropdown control**: a closed trigger showing either the chosen
|
|
13
|
+
option's label or a placeholder, with a small indicator glyph (chevron, caret) hinting it opens a list.
|
|
14
|
+
Clicking or tapping it reveals a floating popup listing the choices; the popup is not part of the
|
|
15
|
+
resting layout — it does not appear in a screenshot of the closed state. The image is the source of
|
|
16
|
+
truth for layout.
|
|
17
|
+
|
|
18
|
+
Signals that distinguish it from other controls:
|
|
19
|
+
|
|
20
|
+
- A **bordered, button-like box** with a text label and a trailing chevron/caret glyph (`▾`, `⌄`, an
|
|
21
|
+
SVG arrow) — not a checkbox square, not a radio circle, not a toggle track.
|
|
22
|
+
- The label inside reads like a **chosen value** (a country name, a size, a sort order), not a
|
|
23
|
+
static caption — a static caption next to the box is the field's label, rendered separately.
|
|
24
|
+
- Grouped variants show a **section heading** inside the popup (`SelectGroupLabel`) above a cluster of
|
|
25
|
+
related options, with a divider line (`SelectSeparator`) between groups.
|
|
26
|
+
- A **country/region selector** (ISO codes resolved to display names), a **sort-order dropdown**, or a
|
|
27
|
+
**quantity/unit picker** are the most common PDP/checkout uses.
|
|
28
|
+
|
|
29
|
+
This particle currently has no `store-editor` knowledge-base row: it is a leaf control with no
|
|
30
|
+
distinct visual region of its own, and the bound `FieldSelect.*` parts cannot be generated from a
|
|
31
|
+
screenshot without the bound Control that consumes them (`ShippingAddressCountryControl`). This section documents the
|
|
32
|
+
visual pattern for a human reader; it is not wired into image→schema detection.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## When to use
|
|
37
|
+
|
|
38
|
+
- Any field whose value is chosen from a closed, platform- or merchant-defined list: country, state,
|
|
39
|
+
sort order, page size, unit, saved-address selection.
|
|
40
|
+
- `FieldSelect.*` specifically: a select whose value must persist through a react-hook-form submit
|
|
41
|
+
alongside the rest of a form's fields (the same contract every other bound field part uses).
|
|
42
|
+
|
|
43
|
+
## When NOT to use
|
|
44
|
+
|
|
45
|
+
- A boolean toggle → use `Checkbox`/`Field.Checkbox` ([[checkbox]], [[field]]), not a two-option Select.
|
|
46
|
+
- Free text entry → use `Field.Control` ([[field]]).
|
|
47
|
+
- A list of mutually exclusive options **all visible at once** (radio buttons, a swatch row) → Select
|
|
48
|
+
hides the options behind a trigger; use a different particle when the design shows every option
|
|
49
|
+
simultaneously (e.g. `VariantSelector`'s swatches).
|
|
50
|
+
- Authoring the option list yourself in a schema for a bound select → not supported.
|
|
51
|
+
`FieldSelectOptionsDefinition` declares `schema: {}`; the list always comes from the field contract's
|
|
52
|
+
`options`, never from a prop (the platform owns the list; an author only reorders and
|
|
53
|
+
restyles).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Composition
|
|
58
|
+
|
|
59
|
+
### Generic anatomy (fully schema-authorable)
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
SelectRoot (renders no element of its own)
|
|
63
|
+
├── SelectLabel (optional; outside SelectTrigger)
|
|
64
|
+
├── SelectTrigger
|
|
65
|
+
│ ├── SelectValue
|
|
66
|
+
│ └── SelectIcon
|
|
67
|
+
└── SelectPortal (renders no element of its own)
|
|
68
|
+
├── SelectBackdrop (optional; modal dismiss layer)
|
|
69
|
+
└── SelectPositioner
|
|
70
|
+
└── SelectPopup
|
|
71
|
+
├── SelectArrow (optional)
|
|
72
|
+
├── SelectScrollUpArrow (optional)
|
|
73
|
+
├── SelectList
|
|
74
|
+
│ ├── SelectItem
|
|
75
|
+
│ │ ├── SelectItemText
|
|
76
|
+
│ │ └── SelectItemIndicator
|
|
77
|
+
│ ├── SelectSeparator (optional, between groups)
|
|
78
|
+
│ └── SelectGroup (optional, instead of flat SelectItems)
|
|
79
|
+
│ ├── SelectGroupLabel
|
|
80
|
+
│ └── SelectItem …
|
|
81
|
+
└── SelectScrollDownArrow (optional)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Child order reflects visual/DOM order. `SelectLabel` is a sibling of `SelectTrigger`, not a child of it —
|
|
85
|
+
screen readers announce it separately. `SelectRoot` and `SelectPortal` render no host element of their
|
|
86
|
+
own (Base UI: *"Doesn't render its own HTML element"*), so neither can carry a `className` or a styling
|
|
87
|
+
hook — style `SelectTrigger`/`SelectPositioner`/`SelectPopup` instead.
|
|
88
|
+
|
|
89
|
+
### Bound anatomy (`FieldSelect.*`)
|
|
90
|
+
|
|
91
|
+
`FieldSelectRoot` recomposes exactly the same generic tree; the difference is which four nodes read the
|
|
92
|
+
enclosing field contract instead of taking props directly. Childless, it renders the full nine-node
|
|
93
|
+
default:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
FieldSelectRoot (drives SelectRoot; requires a field contract + react-hook-form)
|
|
97
|
+
├── FieldSelectTrigger (renders SelectTrigger)
|
|
98
|
+
│ ├── FieldSelectValue (renders SelectValue, label resolved from contract.options)
|
|
99
|
+
│ └── SelectIcon (generic; no default glyph)
|
|
100
|
+
└── SelectPortal
|
|
101
|
+
└── SelectPositioner
|
|
102
|
+
└── SelectPopup
|
|
103
|
+
└── SelectList
|
|
104
|
+
└── FieldSelectOptions (renders one SelectItem per contract.options entry)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Given children, `FieldSelectRoot` renders them instead and steps aside — an author places
|
|
108
|
+
`FieldSelect.Trigger`/`Value`/`Options` anywhere among the generic `Select.*` parts (icon before value,
|
|
109
|
+
an error above the trigger, a custom item indicator) and the binding still works, because **a node gets
|
|
110
|
+
a bound part if and only if the field contract has something to say about it**: the root (identity, seed,
|
|
111
|
+
rule, input semantics), the trigger (requiredness), the value (options → label, placeholder), the item
|
|
112
|
+
list (options). Every other node — icon, portal, positioner, popup, list, arrows, group, separator,
|
|
113
|
+
item indicator — stays the plain generic part; nothing about it is duplicated for the bound anatomy.
|
|
114
|
+
|
|
115
|
+
`FieldSelectOptions` renders no wrapper of its own: it iterates `contract.options` and emits that many
|
|
116
|
+
`SelectItem`s directly into whatever container holds it (normally `SelectList`).
|
|
117
|
+
|
|
118
|
+
**A schema-authored `FieldSelectRoot` compiles but does not bind on its own.** `requiresContext: 'field'`
|
|
119
|
+
is a compiler check satisfied by any ancestor declaring `providesContext: 'field'` (`FieldRootDefinition`
|
|
120
|
+
does) — but the actual field contract is supplied at runtime only by `FieldBinding`, a code-level export
|
|
121
|
+
that is never catalogued (see [[field]]). A schema places `FieldRoot > FieldSelectRoot` and it renders —
|
|
122
|
+
identically to a plain `SelectRoot`, with no seeded value and nothing persisted — because there is no
|
|
123
|
+
`FieldBinding` above it at runtime. Bound behaviour only exists where a matter's own code renders
|
|
124
|
+
`FieldBinding` internally (the pattern `ShippingAddressCountryControl` follows).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Components
|
|
129
|
+
|
|
130
|
+
### SelectRoot
|
|
131
|
+
|
|
132
|
+
Root of the dropdown. Manages selection state, modal overlay, and hidden-input form integration.
|
|
133
|
+
Renders no element of its own.
|
|
134
|
+
|
|
135
|
+
| Prop | Type | Default | Notes |
|
|
136
|
+
|------|------|---------|-------|
|
|
137
|
+
| `disabled` | boolean | `false` | Prevents the popup from opening. |
|
|
138
|
+
| `modal` | boolean | `true` | `false` allows interacting with background elements while open. |
|
|
139
|
+
| `required` | boolean | `false` | Sets `aria-required` on the trigger **and** native `required` on the hidden input — see *Common mistakes*. |
|
|
140
|
+
| `readOnly` | boolean | `false` | |
|
|
141
|
+
| `value` / `defaultValue` | string | — | Controlled / uncontrolled selection. |
|
|
142
|
+
| `onValueChange` | `(value: string \| null) => void` | — | Called with the chosen item's `value`, or `null` when cleared. |
|
|
143
|
+
| `open` / `defaultOpen` / `onOpenChange` | — | | Popup open state, controlled or uncontrolled. |
|
|
144
|
+
| `name` | string | — | Name of the hidden `<input>` Base UI renders for native form participation. |
|
|
145
|
+
| `autoComplete` | string | — | Forwarded to the hidden `<input>`; turns on browser autofill for the field. |
|
|
146
|
+
|
|
147
|
+
### SelectLabel
|
|
148
|
+
|
|
149
|
+
Accessible label for the trigger. No props beyond `className`/`children`. Always a sibling of
|
|
150
|
+
`SelectTrigger`, never a child of it.
|
|
151
|
+
|
|
152
|
+
### SelectTrigger
|
|
153
|
+
|
|
154
|
+
Opens/closes the popup on click. Style `data-open` and `data-placeholder` for open-state and
|
|
155
|
+
empty-state styling.
|
|
156
|
+
|
|
157
|
+
| Prop | Type | Default | Notes |
|
|
158
|
+
|------|------|---------|-------|
|
|
159
|
+
| `disabled` | boolean | `false` | |
|
|
160
|
+
|
|
161
|
+
### SelectValue
|
|
162
|
+
|
|
163
|
+
Renders the selected item's text, or the placeholder when nothing is selected.
|
|
164
|
+
|
|
165
|
+
| Prop | Type | Default | Notes |
|
|
166
|
+
|------|------|---------|-------|
|
|
167
|
+
| `placeholder` | string | — | Shown when nothing is selected and no function child overrides it. |
|
|
168
|
+
| `children` | `ReactNode \| ((value: string \| null) => ReactNode)` | — | **A function child is required for the label to be correct before the shopper opens the dropdown at least once — see the measured-behaviour note below.** |
|
|
169
|
+
|
|
170
|
+
**Measured behaviour, pinned by `select.test.tsx`:** with no function child and no `items` prop on
|
|
171
|
+
`SelectRoot`, `SelectValue` shows the *raw stored value*, not the matching option's label — permanently,
|
|
172
|
+
not merely on first paint. Base UI resolves the label through `resolveSelectedLabel(value, items, …)`;
|
|
173
|
+
`items` is fed only by `SelectRoot`'s own `items` prop (unsupported by this wrapper — see *Common
|
|
174
|
+
mistakes*) and never by a mounted `SelectItem`, so opening and closing the popup does not repair it.
|
|
175
|
+
`FieldSelectValue` exists precisely to carry this resolution with the part; a plain `SelectValue` in a
|
|
176
|
+
hand-composed anatomy needs its own function child.
|
|
177
|
+
|
|
178
|
+
### SelectIcon
|
|
179
|
+
|
|
180
|
+
Decorative glyph (chevron, arrow) inside the trigger. Renders with no children by default — a brand
|
|
181
|
+
supplies the glyph. Style `data-open` to rotate/swap it.
|
|
182
|
+
|
|
183
|
+
### SelectPortal
|
|
184
|
+
|
|
185
|
+
Teleports the popup subtree to `<body>`. Renders no element of its own. Always wrap
|
|
186
|
+
`SelectPositioner` with it.
|
|
187
|
+
|
|
188
|
+
### SelectBackdrop
|
|
189
|
+
|
|
190
|
+
Invisible overlay that closes the select on outside click. Required when `modal={true}` to trap
|
|
191
|
+
interaction.
|
|
192
|
+
|
|
193
|
+
### SelectPositioner
|
|
194
|
+
|
|
195
|
+
Positions the popup relative to the trigger.
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Notes |
|
|
198
|
+
|------|------|---------|-------|
|
|
199
|
+
| `side` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | |
|
|
200
|
+
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | |
|
|
201
|
+
| `sideOffset` | number | `0` | |
|
|
202
|
+
| `alignItemWithTrigger` | boolean | `true` | Overlaps the selected item visually with the trigger. |
|
|
203
|
+
|
|
204
|
+
### SelectPopup
|
|
205
|
+
|
|
206
|
+
Visible container for the list. Style background, border, shadow here.
|
|
207
|
+
|
|
208
|
+
### SelectArrow
|
|
209
|
+
|
|
210
|
+
Pointing arrow attached to the popup. Optional — omit when the design has no anchor arrow.
|
|
211
|
+
|
|
212
|
+
### SelectList
|
|
213
|
+
|
|
214
|
+
Scrollable container for `SelectItem`s (and, when grouped, `SelectGroup`s).
|
|
215
|
+
|
|
216
|
+
### SelectItem
|
|
217
|
+
|
|
218
|
+
One selectable option.
|
|
219
|
+
|
|
220
|
+
| Prop | Type | Default | Notes |
|
|
221
|
+
|------|------|---------|-------|
|
|
222
|
+
| `value` | string | — | Required for the item to be selectable. |
|
|
223
|
+
| `disabled` | boolean | `false` | |
|
|
224
|
+
| `label` | string | — | Used by Base UI for keyboard typeahead matching — not the same mechanism as the trigger's label resolution (see `SelectValue` above). |
|
|
225
|
+
|
|
226
|
+
Style `data-selected`/`data-highlighted` for state.
|
|
227
|
+
|
|
228
|
+
### SelectItemText
|
|
229
|
+
|
|
230
|
+
The item's visible text. Base UI also uses this node for keyboard-typeahead matching.
|
|
231
|
+
|
|
232
|
+
### SelectItemIndicator
|
|
233
|
+
|
|
234
|
+
Checkmark or similar, shown only when the item is selected (`keepMounted` to animate in/out instead
|
|
235
|
+
of unmounting).
|
|
236
|
+
|
|
237
|
+
### SelectSeparator
|
|
238
|
+
|
|
239
|
+
Visual divider, typically between option groups.
|
|
240
|
+
|
|
241
|
+
### SelectGroup
|
|
242
|
+
|
|
243
|
+
Groups related items under a shared `SelectGroupLabel`.
|
|
244
|
+
|
|
245
|
+
### SelectGroupLabel
|
|
246
|
+
|
|
247
|
+
Non-interactive label for a `SelectGroup`, announced by screen readers as the group name.
|
|
248
|
+
|
|
249
|
+
### SelectScrollUpArrow / SelectScrollDownArrow
|
|
250
|
+
|
|
251
|
+
Hover targets that scroll an overflowing list. Appear automatically when the list overflows in that
|
|
252
|
+
direction; `keepMounted` forces them to always render.
|
|
253
|
+
|
|
254
|
+
### FieldSelectRoot
|
|
255
|
+
|
|
256
|
+
Bound select over the shipped `Select` particle: reads the enclosing field contract, registers with
|
|
257
|
+
react-hook-form via `useController({ name, rules, defaultValue })`, and drives `SelectRoot`. Requires a
|
|
258
|
+
field contract (`requiresContext: 'field'`); additionally requires a react-hook-form context to take its
|
|
259
|
+
bound path — with a contract but no `FormProvider`, it
|
|
260
|
+
renders an uncontrolled `SelectRoot` with the given children (or the default anatomy), still honouring
|
|
261
|
+
the contract's static `disabled`/`readOnly` facts, but persisting nothing.
|
|
262
|
+
|
|
263
|
+
| Prop | Type | Default | Notes |
|
|
264
|
+
|------|------|---------|-------|
|
|
265
|
+
| `modal` | boolean | `true` | Forwarded to `SelectRoot`. The one authorable knob that carries no field meaning. |
|
|
266
|
+
| `children` | ReactNode | — | Childless renders the nine-node default anatomy; given children, renders them instead. |
|
|
267
|
+
|
|
268
|
+
Bound behaviour: `value={typeof field.value === 'string' ? field.value : ''}`,
|
|
269
|
+
`onValueChange={(next) => field.onChange(next ?? '')}` — Base UI's `null` (a cleared selection) is
|
|
270
|
+
always normalised to `''` before reaching react-hook-form, never left as `null`. Also passes
|
|
271
|
+
`disabled`/`readOnly`/`name`/`autoComplete` from the contract. Renders **no** `data-fs-field-select-*` hook of its own —
|
|
272
|
+
`SelectRoot` renders no element to put one on (Decision 8); style the bound select through
|
|
273
|
+
`FieldSelectTrigger` instead.
|
|
274
|
+
|
|
275
|
+
### FieldSelectTrigger
|
|
276
|
+
|
|
277
|
+
Bound trigger: renders `SelectTrigger` with `aria-required={contract.rule?.required ? true : undefined}`
|
|
278
|
+
and the styling hook `data-fs-field-select-trigger=""`, alongside the generic
|
|
279
|
+
`data-fs-select-trigger=""`. Requires a field contract; does **not** additionally require
|
|
280
|
+
react-hook-form (Decision 4) — `aria-required` is static contract data.
|
|
281
|
+
|
|
282
|
+
Never passes native `required` to `SelectRoot` — only `aria-required`. A native `required` would also
|
|
283
|
+
mark Base UI's hidden input `required`, turning on browser constraint validation, which fires before
|
|
284
|
+
react-hook-form's `handleSubmit` and would show a native validation bubble instead of `Field.Error`.
|
|
285
|
+
|
|
286
|
+
No props beyond standard button attributes (`className`, `children`).
|
|
287
|
+
|
|
288
|
+
### FieldSelectValue
|
|
289
|
+
|
|
290
|
+
Bound value: renders `SelectValue` with a function child that resolves the current selection's label
|
|
291
|
+
from `contract.options`, plus `data-fs-field-select-value=""` alongside the generic
|
|
292
|
+
`data-fs-select-value=""`. This is the part that closes the measured-behaviour gap noted under
|
|
293
|
+
`SelectValue` above — the resolution travels with the part, so a recomposed anatomy that places
|
|
294
|
+
`FieldSelectValue` gets a correct label on first paint, not only after the dropdown has been opened.
|
|
295
|
+
|
|
296
|
+
| Prop | Type | Default | Notes |
|
|
297
|
+
|------|------|---------|-------|
|
|
298
|
+
| `placeholder` | string | — | Wins over the contract's `placeholder` when given. Shown for an empty value. |
|
|
299
|
+
|
|
300
|
+
Resolution order for the trigger's text: empty value → `placeholder ?? contract.placeholder`; a value
|
|
301
|
+
matching a `contract.options` entry → that option's `label`; a value matching nothing → the raw value
|
|
302
|
+
itself (never blank).
|
|
303
|
+
|
|
304
|
+
### FieldSelectOptions
|
|
305
|
+
|
|
306
|
+
Bound option list: renders one `SelectItem` per `contract.options` entry, in contract order, each
|
|
307
|
+
containing a `SelectItemText` (the option's label — platform data, not authored) followed by whatever
|
|
308
|
+
`children` this part was given (e.g. a `SelectItemIndicator`). Renders `null` when the contract carries
|
|
309
|
+
no `options`, without throwing. Renders no wrapper of its own — items land directly in whatever contains
|
|
310
|
+
this part (normally `SelectList`).
|
|
311
|
+
|
|
312
|
+
| Prop | Type | Default | Notes |
|
|
313
|
+
|------|------|---------|-------|
|
|
314
|
+
| `className` | string | — | Applied to every item this part renders. |
|
|
315
|
+
| `children` | ReactNode | — | Rendered inside every item, after its text. |
|
|
316
|
+
|
|
317
|
+
Every rendered item carries `data-fs-field-select-option=""` alongside the generic
|
|
318
|
+
`data-fs-select-item=""`.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Canonical schema example
|
|
323
|
+
|
|
324
|
+
`FieldBinding` is never catalogued, so the only composition a schema can *bind* is the generic anatomy —
|
|
325
|
+
the same shape below works whether or not a `FieldSelectRoot` happens to sit above it, because without a
|
|
326
|
+
real `FieldBinding` at runtime a schema-authored `FieldSelectRoot` renders unbound (see *Composition*
|
|
327
|
+
above):
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"country-select": {
|
|
332
|
+
"type": "SelectRoot",
|
|
333
|
+
"children": ["country-label", "country-trigger", "country-portal"]
|
|
334
|
+
},
|
|
335
|
+
"country-label": { "type": "SelectLabel", "props": { "children": "Country" } },
|
|
336
|
+
"country-trigger": {
|
|
337
|
+
"type": "SelectTrigger",
|
|
338
|
+
"children": ["country-value", "country-icon"]
|
|
339
|
+
},
|
|
340
|
+
"country-value": { "type": "SelectValue", "props": { "placeholder": "Choose…" } },
|
|
341
|
+
"country-icon": { "type": "SelectIcon", "props": { "children": "▾" } },
|
|
342
|
+
"country-portal": {
|
|
343
|
+
"type": "SelectPortal",
|
|
344
|
+
"children": ["country-positioner"]
|
|
345
|
+
},
|
|
346
|
+
"country-positioner": {
|
|
347
|
+
"type": "SelectPositioner",
|
|
348
|
+
"children": ["country-popup"]
|
|
349
|
+
},
|
|
350
|
+
"country-popup": {
|
|
351
|
+
"type": "SelectPopup",
|
|
352
|
+
"children": ["country-list"]
|
|
353
|
+
},
|
|
354
|
+
"country-list": {
|
|
355
|
+
"type": "SelectList",
|
|
356
|
+
"children": ["country-brazil", "country-usa"]
|
|
357
|
+
},
|
|
358
|
+
"country-brazil": {
|
|
359
|
+
"type": "SelectItem",
|
|
360
|
+
"props": { "value": "BRA", "label": "Brasil" },
|
|
361
|
+
"children": ["country-brazil-text"]
|
|
362
|
+
},
|
|
363
|
+
"country-brazil-text": { "type": "SelectItemText", "props": { "children": "Brasil" } },
|
|
364
|
+
"country-usa": {
|
|
365
|
+
"type": "SelectItem",
|
|
366
|
+
"props": { "value": "USA", "label": "Estados Unidos" },
|
|
367
|
+
"children": ["country-usa-text"]
|
|
368
|
+
},
|
|
369
|
+
"country-usa-text": { "type": "SelectItemText", "props": { "children": "Estados Unidos" } }
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Note the absence of a function child on `country-value` above: authored this way — plainly, with no
|
|
374
|
+
`items` on `country-select` — the trigger shows the raw `value` string until (and after) a function
|
|
375
|
+
child is added, per the measured behaviour documented under `SelectValue`. A bound composition
|
|
376
|
+
(`FieldSelectRoot` given real `FieldBinding` at runtime, as `ShippingAddressCountryControl` does) does
|
|
377
|
+
not have this problem, because `FieldSelectValue` supplies the function child itself.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Common mistakes
|
|
382
|
+
|
|
383
|
+
- **Expecting `SelectValue` to resolve the label automatically once the popup has been opened.** It does
|
|
384
|
+
not, in `@base-ui/react@1.3.0` — see the measured-behaviour note under `SelectValue`. Pass a function
|
|
385
|
+
child, or use `FieldSelectValue` in a bound composition.
|
|
386
|
+
- **Passing `required` to `SelectRoot` expecting only `aria-required`.** It also sets native `required`
|
|
387
|
+
on the hidden input, enabling browser constraint validation that pre-empts react-hook-form's
|
|
388
|
+
`handleSubmit`. Use `FieldSelectTrigger`'s `aria-required` (or a manual `aria-required` prop) instead.
|
|
389
|
+
- **Putting a `className` or a `data-fs-*` hook expectation on `SelectRoot` or `SelectPortal`.** Neither
|
|
390
|
+
renders an element — the prop is silently dropped. Style `SelectTrigger`/`SelectPositioner`/
|
|
391
|
+
`SelectPopup` instead.
|
|
392
|
+
- **Authoring an `options` prop on `FieldSelectOptions`.** There is none —
|
|
393
|
+
`FieldSelectOptionsDefinition` declares `schema: {}`. The option list always comes from the field
|
|
394
|
+
contract, never from a prop.
|
|
395
|
+
- **Expecting a schema-authored `FieldSelectRoot` to bind just because a `FieldRoot` sits above it.**
|
|
396
|
+
The compiler's context check passes, but nothing supplies a live contract at runtime without a real
|
|
397
|
+
`FieldBinding`, which only a matter's own code renders. The result compiles green and behaves like a
|
|
398
|
+
plain, unseeded `SelectRoot`.
|
|
399
|
+
- **Nesting the field name as a prop anywhere under `FieldSelectRoot`.** No `FieldSelect.*` part accepts
|
|
400
|
+
one; the only way to name a field is a `FieldBinding` above it.
|
|
401
|
+
- **Reordering `SelectItemText`/`SelectItemIndicator` inside a `FieldSelectOptions`-rendered item.**
|
|
402
|
+
`FieldSelectOptions` fixes the text first, `children` after — a different order for the indicator is a
|
|
403
|
+
CSS `order`/`flex-direction` concern on `[data-fs-select-item-text]`/`[data-fs-select-item-indicator]`,
|
|
404
|
+
not a composition option.
|
|
405
|
+
- **Using `Field.Select`.** There is no such member. The bound namespace is `FieldSelect` (`FieldSelect
|
|
406
|
+
.Root/.Trigger/.Value/.Options`), ships from this directory, and is not part of the `Field` namespace —
|
|
407
|
+
a deliberate naming divergence.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Styling
|
|
412
|
+
|
|
413
|
+
`SelectRoot` and `SelectPortal` render no element and cannot be styled directly — style the parts that
|
|
414
|
+
do.
|
|
415
|
+
|
|
416
|
+
| Component | What you style | Plausible classes |
|
|
417
|
+
|---|---|---|
|
|
418
|
+
| `SelectTrigger` | The closed control's box | `inline-flex items-center gap-2 border border-gray-300 rounded-md px-3 py-2 text-sm bg-white hover:border-gray-400 data-open:border-blue-500` |
|
|
419
|
+
| `SelectValue` | The chosen label / placeholder text | `flex-1 text-left` (target `data-placeholder:text-gray-400` for the empty state) |
|
|
420
|
+
| `SelectIcon` | The trailing glyph | `text-gray-400` |
|
|
421
|
+
| `SelectPopup` | The floating panel | `bg-white border border-gray-200 rounded-md shadow-lg overflow-hidden` |
|
|
422
|
+
| `SelectList` | The scrollable list | `py-1 max-h-60 overflow-auto` |
|
|
423
|
+
| `SelectItem` | One option row | `flex items-center gap-2 px-3 py-2 text-sm cursor-default hover:bg-blue-50 data-highlighted:bg-blue-50 data-selected:text-blue-600` |
|
|
424
|
+
| `SelectGroupLabel` | A group heading inside the list | `px-3 py-1 text-xs font-semibold text-gray-500 uppercase tracking-wide` |
|
|
425
|
+
| `SelectSeparator` | The divider between groups | `my-1 border-t border-gray-100` |
|
|
426
|
+
|
|
427
|
+
The four `FieldSelect.*` parts render alongside their generic counterpart's own hook
|
|
428
|
+
(`FieldSelectTrigger` on the same `<button>` as `SelectTrigger`, and so on) — style through the generic
|
|
429
|
+
class names above; the bound `data-fs-field-select-*` attributes exist for a brand that specifically
|
|
430
|
+
needs to target *the bound select* without touching every generic select in the app.
|
|
431
|
+
|
|
432
|
+
Styled bound example (the `BoundRecomposed` story):
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
<FieldSelect.Root>
|
|
436
|
+
<FieldSelect.Trigger className="inline-flex items-center gap-2 border border-gray-300 rounded-md px-3 py-2 text-sm bg-white hover:border-gray-400 data-open:border-blue-500">
|
|
437
|
+
<SelectIcon className="text-gray-400">▾</SelectIcon>
|
|
438
|
+
<FieldSelect.Value className="flex-1 text-left" />
|
|
439
|
+
</FieldSelect.Trigger>
|
|
440
|
+
<SelectPortal>
|
|
441
|
+
<SelectPositioner>
|
|
442
|
+
<SelectPopup className="bg-white border border-gray-200 rounded-md shadow-lg overflow-hidden">
|
|
443
|
+
<SelectList className="py-1 max-h-60 overflow-auto">
|
|
444
|
+
<FieldSelect.Options className="flex items-center gap-2 px-3 py-2 text-sm cursor-default hover:bg-blue-50 data-highlighted:bg-blue-50 data-selected:text-blue-600">
|
|
445
|
+
<SelectItemIndicator className="w-4 text-blue-600">✓</SelectItemIndicator>
|
|
446
|
+
</FieldSelect.Options>
|
|
447
|
+
</SelectList>
|
|
448
|
+
</SelectPopup>
|
|
449
|
+
</SelectPositioner>
|
|
450
|
+
</SelectPortal>
|
|
451
|
+
</FieldSelect.Root>
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Related
|
|
457
|
+
|
|
458
|
+
- [[field]] — the field contract (`FieldBinding`/`useField`, `FieldContract`, `FieldOption`) that
|
|
459
|
+
`FieldSelect.*` consumes. The `Field` namespace itself gains no `Select` member — see *Common
|
|
460
|
+
mistakes* above.
|
|
461
|
+
- [[checkbox]] — the sibling bound part for a boolean field is `Field.Checkbox` (lives in `field.tsx`,
|
|
462
|
+
not here); `FieldSelect.*` is the equivalent family for a chosen-option field, kept in its own
|
|
463
|
+
directory.
|
|
464
|
+
- `ShippingAddressCountryControl` (`packages/faststore/src/matter/shipping-address/shipping-address.tsx`)
|
|
465
|
+
— today's only select in the repo, and the only consumer of `FieldSelect.*`.
|
package/dist/docs/session.md
CHANGED
|
@@ -34,7 +34,7 @@ Exactly one `SessionRoot` per rendered tree. A layout-hosted provider already co
|
|
|
34
34
|
## Layout hosting vs. page hosting
|
|
35
35
|
|
|
36
36
|
Layout and page scope still fetch differently, even though both now see the shopper's cookie
|
|
37
|
-
([
|
|
37
|
+
([SSR session cookie forwarding](../../../../../docs/storefront-core/reference-ssr-session-cookie-forwarding.md)):
|
|
38
38
|
|
|
39
39
|
- **Layout scope** emits `LAYOUT_QUERY` inside a client component with no SSR seed — no `serverVariables`, no
|
|
40
40
|
`initialData`. The read happens once in the browser and is reused from cache across client-side navigation.
|