@coinbase/cds-mcp-server 8.28.1 → 8.29.0

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.
Files changed (82) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/mcp-docs/mobile/components/Accordion.txt +3 -1
  3. package/mcp-docs/mobile/components/Alert.txt +3 -1
  4. package/mcp-docs/mobile/components/Banner.txt +14 -14
  5. package/mcp-docs/mobile/components/Button.txt +173 -30
  6. package/mcp-docs/mobile/components/Carousel.txt +24 -24
  7. package/mcp-docs/mobile/components/Combobox.txt +187 -0
  8. package/mcp-docs/mobile/components/ContainedAssetCard.txt +4 -4
  9. package/mcp-docs/mobile/components/ContentCard.txt +29 -27
  10. package/mcp-docs/mobile/components/ContentCardBody.txt +4 -4
  11. package/mcp-docs/mobile/components/ContentCardHeader.txt +2 -2
  12. package/mcp-docs/mobile/components/FloatingAssetCard.txt +6 -6
  13. package/mcp-docs/mobile/components/IconButton.txt +126 -51
  14. package/mcp-docs/mobile/components/LineChart.txt +3 -2
  15. package/mcp-docs/mobile/components/MultiContentModule.txt +6 -6
  16. package/mcp-docs/mobile/components/Numpad.txt +2 -2
  17. package/mcp-docs/mobile/components/PageHeader.txt +3 -1
  18. package/mcp-docs/mobile/components/PeriodSelector.txt +4 -4
  19. package/mcp-docs/mobile/components/Pressable.txt +6 -2
  20. package/mcp-docs/mobile/components/ProgressBarWithFixedLabels.txt +4 -4
  21. package/mcp-docs/mobile/components/ProgressBarWithFloatLabel.txt +2 -2
  22. package/mcp-docs/mobile/components/ProgressCircle.txt +5 -1
  23. package/mcp-docs/mobile/components/SelectChip.txt +2 -0
  24. package/mcp-docs/mobile/components/SelectChipAlpha.txt +1 -1
  25. package/mcp-docs/mobile/components/SlideButton.txt +2 -2
  26. package/mcp-docs/mobile/components/Sparkline.txt +3 -1
  27. package/mcp-docs/mobile/components/SparklineGradient.txt +3 -1
  28. package/mcp-docs/mobile/components/SparklineInteractiveHeader.txt +3 -1
  29. package/mcp-docs/mobile/components/TabbedChips.txt +3 -1
  30. package/mcp-docs/mobile/components/Tag.txt +19 -9
  31. package/mcp-docs/mobile/components/TextInput.txt +9 -3
  32. package/mcp-docs/mobile/components/Tray.txt +2 -0
  33. package/mcp-docs/mobile/components/UpsellCard.txt +16 -16
  34. package/mcp-docs/mobile/hooks/useDimensions.txt +4 -4
  35. package/mcp-docs/mobile/hooks/useMergeRefs.txt +4 -4
  36. package/mcp-docs/mobile/hooks/usePreviousValue.txt +5 -5
  37. package/mcp-docs/mobile/hooks/useRefMap.txt +6 -6
  38. package/mcp-docs/mobile/routes.txt +1 -0
  39. package/mcp-docs/web/components/Accordion.txt +3 -1
  40. package/mcp-docs/web/components/Alert.txt +3 -1
  41. package/mcp-docs/web/components/Banner.txt +14 -14
  42. package/mcp-docs/web/components/Button.txt +188 -34
  43. package/mcp-docs/web/components/Carousel.txt +71 -65
  44. package/mcp-docs/web/components/Combobox.txt +176 -0
  45. package/mcp-docs/web/components/ContainedAssetCard.txt +4 -4
  46. package/mcp-docs/web/components/ContentCard.txt +29 -27
  47. package/mcp-docs/web/components/ContentCardBody.txt +4 -4
  48. package/mcp-docs/web/components/ContentCardHeader.txt +2 -2
  49. package/mcp-docs/web/components/FloatingAssetCard.txt +6 -6
  50. package/mcp-docs/web/components/FullscreenModal.txt +12 -4
  51. package/mcp-docs/web/components/GridColumn.txt +12 -4
  52. package/mcp-docs/web/components/IconButton.txt +164 -189
  53. package/mcp-docs/web/components/LineChart.txt +3 -2
  54. package/mcp-docs/web/components/MultiContentModule.txt +6 -6
  55. package/mcp-docs/web/components/PageHeader.txt +11 -9
  56. package/mcp-docs/web/components/ProgressBarWithFixedLabels.txt +4 -4
  57. package/mcp-docs/web/components/ProgressBarWithFloatLabel.txt +2 -2
  58. package/mcp-docs/web/components/ProgressCircle.txt +5 -1
  59. package/mcp-docs/web/components/SelectChipAlpha.txt +1 -1
  60. package/mcp-docs/web/components/Sidebar.txt +2 -2
  61. package/mcp-docs/web/components/Sparkline.txt +3 -1
  62. package/mcp-docs/web/components/SparklineGradient.txt +3 -1
  63. package/mcp-docs/web/components/SparklineInteractiveHeader.txt +3 -1
  64. package/mcp-docs/web/components/TabbedChips.txt +3 -1
  65. package/mcp-docs/web/components/TableBody.txt +2 -2
  66. package/mcp-docs/web/components/TableCaption.txt +2 -2
  67. package/mcp-docs/web/components/TableCell.txt +6 -6
  68. package/mcp-docs/web/components/Tag.txt +19 -9
  69. package/mcp-docs/web/components/TextInput.txt +9 -3
  70. package/mcp-docs/web/components/Tray.txt +2 -1
  71. package/mcp-docs/web/components/UpsellCard.txt +16 -16
  72. package/mcp-docs/web/hooks/useDimensions.txt +4 -4
  73. package/mcp-docs/web/hooks/useHasMounted.txt +7 -3
  74. package/mcp-docs/web/hooks/useIsoEffect.txt +1 -1
  75. package/mcp-docs/web/hooks/useMergeRefs.txt +4 -4
  76. package/mcp-docs/web/hooks/useOverlayContentContext.txt +8 -8
  77. package/mcp-docs/web/hooks/usePreviousValue.txt +5 -5
  78. package/mcp-docs/web/hooks/useRefMap.txt +6 -6
  79. package/mcp-docs/web/hooks/useScrollBlocker.txt +1 -1
  80. package/mcp-docs/web/hooks/useTheme.txt +3 -3
  81. package/mcp-docs/web/routes.txt +1 -0
  82. package/package.json +1 -1
@@ -32,9 +32,9 @@ function MyCarousel() {
32
32
  return (
33
33
  <ContainedAssetCard
34
34
  description={
35
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
35
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
36
36
  ↗6.37%
37
- </TextLabel2>
37
+ </Text>
38
38
  }
39
39
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
40
40
  subtitle={name}
@@ -113,7 +113,9 @@ function DynamicSizingCarousel() {
113
113
  return (
114
114
  <VStack gap={2}>
115
115
  <HStack justifyContent="flex-end" gap={2} alignItems="center">
116
- <TextHeadline as="h3">Items per page</TextHeadline>
116
+ <Text as="h3" font="headline">
117
+ Items per page
118
+ </Text>
117
119
  <SegmentedTabs
118
120
  activeTab={selectedItemsPerPage}
119
121
  onChange={setSelectedItemsPerPage}
@@ -146,9 +148,9 @@ function DynamicSizingCarousel() {
146
148
  }
147
149
  minWidth="0"
148
150
  title={
149
- <TextHeadline as="h3" id="recurring-buy-label">
151
+ <Text as="h3" font="headline" id="recurring-buy-label">
150
152
  Recurring Buy
151
- </TextHeadline>
153
+ </Text>
152
154
  }
153
155
  width="100%"
154
156
  />
@@ -164,9 +166,9 @@ function DynamicSizingCarousel() {
164
166
  action={<ActionButton isVisible={isVisible}>Start earning</ActionButton>}
165
167
  dangerouslySetBackground="rgb(var(--purple70))"
166
168
  description={
167
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
169
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
168
170
  Earn staking rewards on ETH by holding it on Coinbase
169
- </TextLabel2>
171
+ </Text>
170
172
  }
171
173
  media={
172
174
  <Box left={16} position="relative" top={12}>
@@ -175,9 +177,9 @@ function DynamicSizingCarousel() {
175
177
  }
176
178
  minWidth="0"
177
179
  title={
178
- <TextHeadline id="eths-apr-label" color="fgInverse" as="h3">
180
+ <Text id="eths-apr-label" color="fgInverse" as="h3">
179
181
  Up to 3.29% APR on ETHs
180
- </TextHeadline>
182
+ </Text>
181
183
  }
182
184
  width="100%"
183
185
  />
@@ -193,9 +195,9 @@ function DynamicSizingCarousel() {
193
195
  action={<ActionButton isVisible={isVisible}>Start chatting</ActionButton>}
194
196
  dangerouslySetBackground="rgb(var(--teal70))"
195
197
  description={
196
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
198
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
197
199
  Chat with other devs in our Discord community
198
- </TextLabel2>
200
+ </Text>
199
201
  }
200
202
  media={
201
203
  <Box left={16} position="relative" top={4}>
@@ -204,9 +206,9 @@ function DynamicSizingCarousel() {
204
206
  }
205
207
  minWidth="0"
206
208
  title={
207
- <TextHeadline id="join-the-community-label" color="fgInverse" as="h3">
209
+ <Text id="join-the-community-label" color="fgInverse" as="h3">
208
210
  Join the community
209
- </TextHeadline>
211
+ </Text>
210
212
  }
211
213
  width="100%"
212
214
  />
@@ -222,9 +224,9 @@ function DynamicSizingCarousel() {
222
224
  action={<ActionButton isVisible={isVisible}>Get 60 days free</ActionButton>}
223
225
  dangerouslySetBackground="rgb(var(--blue80))"
224
226
  description={
225
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
227
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
226
228
  Use code NOV60 when you sign up for Coinbase One
227
- </TextLabel2>
229
+ </Text>
228
230
  }
229
231
  media={
230
232
  <Box left={16} position="relative" top={0}>
@@ -233,9 +235,9 @@ function DynamicSizingCarousel() {
233
235
  }
234
236
  minWidth="0"
235
237
  title={
236
- <TextHeadline id="coinbase-one-offer-label" color="fgInverse" as="h3">
238
+ <Text id="coinbase-one-offer-label" color="fgInverse" as="h3">
237
239
  Coinbase One offer
238
- </TextHeadline>
240
+ </Text>
239
241
  }
240
242
  width="100%"
241
243
  />
@@ -251,9 +253,9 @@ function DynamicSizingCarousel() {
251
253
  action={<ActionButton isVisible={isVisible}>Get started</ActionButton>}
252
254
  dangerouslySetBackground="rgb(var(--gray100))"
253
255
  description={
254
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
256
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
255
257
  Spend USDC to get rewards with our Visa® debit card
256
- </TextLabel2>
258
+ </Text>
257
259
  }
258
260
  media={
259
261
  <Box left={16} position="relative" top={0}>
@@ -262,9 +264,9 @@ function DynamicSizingCarousel() {
262
264
  }
263
265
  minWidth="0"
264
266
  title={
265
- <TextHeadline id="coinbase-card-label" color="fgInverse" as="h3">
267
+ <Text id="coinbase-card-label" color="fgInverse" as="h3">
266
268
  Coinbase Card
267
- </TextHeadline>
269
+ </Text>
268
270
  }
269
271
  width="100%"
270
272
  />
@@ -367,9 +369,9 @@ function VariedSizingCarousel() {
367
369
  return (
368
370
  <ContainedAssetCard
369
371
  description={
370
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
372
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
371
373
  ↗6.37%
372
- </TextLabel2>
374
+ </Text>
373
375
  }
374
376
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
375
377
  subtitle={name}
@@ -475,9 +477,9 @@ function DragCarousel() {
475
477
  return (
476
478
  <ContainedAssetCard
477
479
  description={
478
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
480
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
479
481
  ↗6.37%
480
- </TextLabel2>
482
+ </Text>
481
483
  }
482
484
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
483
485
  subtitle={name}
@@ -488,7 +490,9 @@ function DragCarousel() {
488
490
  return (
489
491
  <VStack gap={2}>
490
492
  <HStack justifyContent="flex-end" gap={2} alignItems="center">
491
- <TextHeadline as="h3">Drag</TextHeadline>
493
+ <Text as="h3" font="headline">
494
+ Drag
495
+ </Text>
492
496
  <SegmentedTabs activeTab={drag} onChange={setDrag} tabs={dragOptions} />
493
497
  </HStack>
494
498
  <Box style={{ marginInline: 'calc(-1 * var(--space-3))' }}>
@@ -532,9 +536,9 @@ function SnapModeCarousel() {
532
536
  return (
533
537
  <ContainedAssetCard
534
538
  description={
535
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
539
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
536
540
  ↗6.37%
537
- </TextLabel2>
541
+ </Text>
538
542
  }
539
543
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
540
544
  subtitle={name}
@@ -545,7 +549,9 @@ function SnapModeCarousel() {
545
549
  return (
546
550
  <VStack gap={2}>
547
551
  <HStack justifyContent="flex-end" gap={2} alignItems="center">
548
- <TextHeadline as="h3">Snap mode</TextHeadline>
552
+ <Text as="h3" font="headline">
553
+ Snap mode
554
+ </Text>
549
555
  <SegmentedTabs activeTab={snapMode} onChange={setSnapMode} tabs={snapModeOptions} />
550
556
  </HStack>
551
557
  <Box style={{ marginInline: 'calc(-1 * var(--space-3))' }}>
@@ -591,9 +597,9 @@ function OverflowCarousel() {
591
597
  return (
592
598
  <ContainedAssetCard
593
599
  description={
594
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
600
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
595
601
  ↗6.37%
596
- </TextLabel2>
602
+ </Text>
597
603
  }
598
604
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
599
605
  onClick={isVisible ? () => console.log('clicked') : undefined}
@@ -665,9 +671,9 @@ If you have elements that are focusable, you can use `isVisible` render prop to
665
671
  }
666
672
  minWidth="0"
667
673
  title={
668
- <TextHeadline as="h3" id="recurring-buy-label">
674
+ <Text as="h3" font="headline" id="recurring-buy-label">
669
675
  Recurring Buy
670
- </TextHeadline>
676
+ </Text>
671
677
  }
672
678
  width="100%"
673
679
  />
@@ -686,11 +692,11 @@ You can customize the navigation and pagination components of the carousel using
686
692
  function CustomComponentsCarousel() {
687
693
  function SeeAllComponent({ style }) {
688
694
  return (
689
- <TextHeadline style={style}>
695
+ <Text style={style}>
690
696
  <Link openInNewWindow href="https://coinbase.com/">
691
697
  See all
692
698
  </Link>
693
- </TextHeadline>
699
+ </Text>
694
700
  );
695
701
  }
696
702
  function PaginationComponent({ totalPages, activePageIndex, onClickPage, style }) {
@@ -773,9 +779,9 @@ function CustomComponentsCarousel() {
773
779
  carousel: { gap: 'var(--space-1)' },
774
780
  }}
775
781
  title={
776
- <TextHeadline as="h3">
782
+ <Text as="h3" font="headline">
777
783
  Learn more
778
- </TextHeadline>
784
+ </Text>
779
785
  }
780
786
  >
781
787
  <CarouselItem id="recurring-buy" width={itemWidth}>
@@ -800,9 +806,9 @@ function CustomComponentsCarousel() {
800
806
  action={<ActionButton isVisible={isVisible}>Start earning</ActionButton>}
801
807
  dangerouslySetBackground="rgb(var(--purple70))"
802
808
  description={
803
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
809
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
804
810
  Earn staking rewards on ETH by holding it on Coinbase
805
- </TextLabel2>
811
+ </Text>
806
812
  }
807
813
  media={
808
814
  <Box left={16} position="relative" top={12}>
@@ -811,9 +817,9 @@ function CustomComponentsCarousel() {
811
817
  }
812
818
  minWidth="0"
813
819
  title={
814
- <TextHeadline color="fgInverse" as="h3">
820
+ <Text color="fgInverse" as="h3" font="headline">
815
821
  Up to 3.29% APR on ETHs
816
- </TextHeadline>
822
+ </Text>
817
823
  }
818
824
  width="100%"
819
825
  />
@@ -825,9 +831,9 @@ function CustomComponentsCarousel() {
825
831
  action={<ActionButton isVisible={isVisible}>Start chatting</ActionButton>}
826
832
  dangerouslySetBackground="rgb(var(--teal70))"
827
833
  description={
828
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
834
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
829
835
  Chat with other devs in our Discord community
830
- </TextLabel2>
836
+ </Text>
831
837
  }
832
838
  media={
833
839
  <Box left={16} position="relative" top={4}>
@@ -836,9 +842,9 @@ function CustomComponentsCarousel() {
836
842
  }
837
843
  minWidth="0"
838
844
  title={
839
- <TextHeadline color="fgInverse" as="h3">
845
+ <Text color="fgInverse" as="h3" font="headline">
840
846
  Join the community
841
- </TextHeadline>
847
+ </Text>
842
848
  }
843
849
  width="100%"
844
850
  />
@@ -850,9 +856,9 @@ function CustomComponentsCarousel() {
850
856
  action={<ActionButton isVisible={isVisible}>Get 60 days free</ActionButton>}
851
857
  dangerouslySetBackground="rgb(var(--blue80))"
852
858
  description={
853
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
859
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
854
860
  Use code NOV60 when you sign up for Coinbase One
855
- </TextLabel2>
861
+ </Text>
856
862
  }
857
863
  media={
858
864
  <Box left={16} position="relative" top={0}>
@@ -861,9 +867,9 @@ function CustomComponentsCarousel() {
861
867
  }
862
868
  minWidth="0"
863
869
  title={
864
- <TextHeadline color="fgInverse" as="h3">
870
+ <Text color="fgInverse" as="h3" font="headline">
865
871
  Coinbase One offer
866
- </TextHeadline>
872
+ </Text>
867
873
  }
868
874
  width="100%"
869
875
  />
@@ -875,9 +881,9 @@ function CustomComponentsCarousel() {
875
881
  action={<ActionButton isVisible={isVisible}>Get started</ActionButton>}
876
882
  dangerouslySetBackground="rgb(var(--gray100))"
877
883
  description={
878
- <TextLabel2 as="p" numberOfLines={3} color="fgInverse">
884
+ <Text as="p" font="label2" numberOfLines={3} color="fgInverse">
879
885
  Spend USDC to get rewards with our Visa® debit card
880
- </TextLabel2>
886
+ </Text>
881
887
  }
882
888
  media={
883
889
  <Box left={16} position="relative" top={0}>
@@ -886,9 +892,9 @@ function CustomComponentsCarousel() {
886
892
  }
887
893
  minWidth="0"
888
894
  title={
889
- <TextHeadline color="fgInverse" as="h3">
895
+ <Text color="fgInverse" as="h3" font="headline">
890
896
  Coinbase Card
891
- </TextHeadline>
897
+ </Text>
892
898
  }
893
899
  width="100%"
894
900
  />
@@ -1002,9 +1008,9 @@ function DynamicContentCarousel() {
1002
1008
  return (
1003
1009
  <ContainedAssetCard
1004
1010
  description={
1005
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1011
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1006
1012
  ↗6.37%
1007
- </TextLabel2>
1013
+ </Text>
1008
1014
  }
1009
1015
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1010
1016
  subtitle={name}
@@ -1069,9 +1075,9 @@ function AnimatedCarousel() {
1069
1075
  >
1070
1076
  <ContainedAssetCard
1071
1077
  description={
1072
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1078
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1073
1079
  ↗6.37%
1074
- </TextLabel2>
1080
+ </Text>
1075
1081
  }
1076
1082
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1077
1083
  subtitle={name}
@@ -1146,9 +1152,9 @@ function AnimatedSelectionCarousel() {
1146
1152
  >
1147
1153
  <ContainedAssetCard
1148
1154
  description={
1149
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1155
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1150
1156
  ↗6.37%
1151
- </TextLabel2>
1157
+ </Text>
1152
1158
  }
1153
1159
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1154
1160
  subtitle={name}
@@ -1205,9 +1211,9 @@ function HideNavigationAndPaginationCarousel() {
1205
1211
  return (
1206
1212
  <ContainedAssetCard
1207
1213
  description={
1208
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1214
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1209
1215
  ↗6.37%
1210
- </TextLabel2>
1216
+ </Text>
1211
1217
  }
1212
1218
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1213
1219
  subtitle={name}
@@ -1282,9 +1288,9 @@ function AnimatedPaginationCarousel() {
1282
1288
  return (
1283
1289
  <ContainedAssetCard
1284
1290
  description={
1285
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1291
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1286
1292
  ↗6.37%
1287
- </TextLabel2>
1293
+ </Text>
1288
1294
  }
1289
1295
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1290
1296
  subtitle={name}
@@ -1359,9 +1365,9 @@ function ImperativeApiCarousel() {
1359
1365
  return (
1360
1366
  <ContainedAssetCard
1361
1367
  description={
1362
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
1368
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
1363
1369
  ↗6.37%
1364
- </TextLabel2>
1370
+ </Text>
1365
1371
  }
1366
1372
  header={<RemoteImage height="32px" source={imageUrl} width="32px" />}
1367
1373
  subtitle={name}
@@ -0,0 +1,176 @@
1
+ # Combobox
2
+
3
+ A flexible combobox component for both single and multi-selection, built for web applications with comprehensive accessibility support.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Combobox } from '@coinbase/cds-web/alpha/combobox'
9
+ ```
10
+
11
+ ## Examples
12
+
13
+ ### A note on search logic
14
+
15
+ We use [fuse.js](https://www.fusejs.io/) to power the fuzzy search logic for Combobox. You can override this search logic with your own using the `filterFunction` prop.
16
+
17
+ ### Multi-Select
18
+
19
+ Basic multi-selection combobox with search.
20
+
21
+ ```jsx live
22
+ function MultiSelect() {
23
+ const fruitOptions: SelectOption[] = [
24
+ { value: 'apple', label: 'Apple' },
25
+ { value: 'banana', label: 'Banana' },
26
+ { value: 'cherry', label: 'Cherry' },
27
+ { value: 'date', label: 'Date' },
28
+ { value: 'elderberry', label: 'Elderberry' },
29
+ { value: 'fig', label: 'Fig' },
30
+ { value: 'grape', label: 'Grape' },
31
+ { value: 'honeydew', label: 'Honeydew' },
32
+ { value: 'kiwi', label: 'Kiwi' },
33
+ { value: 'lemon', label: 'Lemon' },
34
+ { value: 'mango', label: 'Mango' },
35
+ { value: 'orange', label: 'Orange' },
36
+ { value: 'papaya', label: 'Papaya' },
37
+ { value: 'raspberry', label: 'Raspberry' },
38
+ { value: 'strawberry', label: 'Strawberry' },
39
+ ];
40
+
41
+ const { value, onChange } = useMultiSelect({ initialValue: ['apple', 'banana'] });
42
+
43
+ return (
44
+ <Combobox
45
+ label="Select fruits"
46
+ onChange={onChange}
47
+ options={fruitOptions}
48
+ placeholder="Search and select fruits..."
49
+ type="multi"
50
+ value={value}
51
+ />
52
+ );
53
+ }
54
+ ```
55
+
56
+ ### Single Select
57
+
58
+ Standard single-selection combobox with an option to clear the current value.
59
+
60
+ ```jsx live
61
+ function SingleSelect() {
62
+ const singleSelectOptions = [
63
+ { value: null, label: 'Remove selection' },
64
+ { value: 'apple', label: 'Apple' },
65
+ { value: 'banana', label: 'Banana' },
66
+ { value: 'cherry', label: 'Cherry' },
67
+ { value: 'date', label: 'Date' },
68
+ ];
69
+
70
+ const [value, setValue] = useState('apple');
71
+
72
+ return (
73
+ <Combobox
74
+ label="Favorite fruit"
75
+ onChange={setValue}
76
+ options={singleSelectOptions}
77
+ placeholder="Search fruits..."
78
+ value={value}
79
+ />
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### Helper Text
85
+
86
+ Communicate limits or guidance by pairing helper text with multi-select usage.
87
+
88
+ ```jsx live
89
+ function HelperText() {
90
+ const fruitOptions: SelectOption[] = [
91
+ { value: 'apple', label: 'Apple' },
92
+ { value: 'banana', label: 'Banana' },
93
+ { value: 'cherry', label: 'Cherry' },
94
+ { value: 'date', label: 'Date' },
95
+ { value: 'elderberry', label: 'Elderberry' },
96
+ { value: 'fig', label: 'Fig' },
97
+ { value: 'grape', label: 'Grape' },
98
+ { value: 'honeydew', label: 'Honeydew' },
99
+ { value: 'kiwi', label: 'Kiwi' },
100
+ { value: 'lemon', label: 'Lemon' },
101
+ { value: 'mango', label: 'Mango' },
102
+ { value: 'orange', label: 'Orange' },
103
+ { value: 'papaya', label: 'Papaya' },
104
+ { value: 'raspberry', label: 'Raspberry' },
105
+ { value: 'strawberry', label: 'Strawberry' },
106
+ ];
107
+
108
+ const { value, onChange } = useMultiSelect({ initialValue: ['apple', 'banana'] });
109
+
110
+ return (
111
+ <Combobox
112
+ helperText="Choose more than one fruit"
113
+ label="Select fruits"
114
+ onChange={onChange}
115
+ options={fruitOptions}
116
+ placeholder="Search and select fruits..."
117
+ type="multi"
118
+ value={value}
119
+ />
120
+ );
121
+ }
122
+ ```
123
+
124
+ ## Props
125
+
126
+ | Prop | Type | Required | Default | Description |
127
+ | --- | --- | --- | --- | --- |
128
+ | `onChange` | `(value: Type extends multi ? SelectOptionValue \| SelectOptionValue[] \| null : SelectOptionValue \| null) => void` | Yes | `-` | - |
129
+ | `options` | `SelectOptionList<Type, SelectOptionValue>` | Yes | `-` | Array of options to display in the select dropdown. Can be individual options or groups with label and options |
130
+ | `value` | `string \| SelectOptionValue[] \| null` | Yes | `-` | - |
131
+ | `ComboboxControlComponent` | `ComboboxControlComponent` | No | `-` | Custom ComboboxControlComponent to wrap SelectControlComponent. This component must be a stable reference |
132
+ | `SelectAllOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the Select All option |
133
+ | `SelectControlComponent` | `SelectControlComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the select control |
134
+ | `SelectDropdownComponent` | `SelectDropdownComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the dropdown container |
135
+ | `SelectEmptyDropdownContentsComponent` | `SelectEmptyDropdownContentComponent` | No | `-` | Custom component to render when no options are available |
136
+ | `SelectOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render individual options |
137
+ | `SelectOptionGroupComponent` | `SelectOptionGroupComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render group headers |
138
+ | `accessibilityRoles` | `{ dropdown?: AriaHasPopupType; option?: string \| undefined; } \| undefined` | No | `-` | Accessibility roles for dropdown and option elements |
139
+ | `accessory` | `ReactElement<CellAccessoryProps, string \| JSXElementConstructor<any>>` | No | `-` | Accessory element rendered at the end of the cell (e.g., chevron). |
140
+ | `className` | `string` | No | `-` | CSS class name for the root element |
141
+ | `classNames` | `{ root?: string; control?: string \| undefined; controlStartNode?: string \| undefined; controlInputNode?: string \| undefined; controlValueNode?: string \| undefined; controlLabelNode?: string \| undefined; controlHelperTextNode?: string \| undefined; controlEndNode?: string \| undefined; dropdown?: string \| undefined; option?: string \| undefined; optionCell?: string \| undefined; optionContent?: string \| undefined; optionLabel?: string \| undefined; optionDescription?: string \| undefined; selectAllDivider?: string \| undefined; emptyContentsContainer?: string \| undefined; emptyContentsText?: string \| undefined; optionGroup?: string \| undefined; } \| undefined` | No | `-` | Custom class names for different parts of the select |
142
+ | `clearAllLabel` | `string` | No | `-` | Label for the Clear All option in multi-select mode |
143
+ | `compact` | `boolean` | No | `-` | Whether to use compact styling for the select |
144
+ | `controlAccessibilityLabel` | `string` | No | `-` | Accessibility label for the control |
145
+ | `defaultOpen` | `boolean` | No | `-` | Initial open state when component mounts (uncontrolled mode) |
146
+ | `defaultSearchText` | `string` | No | `-` | Default search text value for uncontrolled mode |
147
+ | `disableClickOutsideClose` | `boolean` | No | `-` | Whether clicking outside the dropdown should close it |
148
+ | `disabled` | `boolean` | No | `false` | Toggles input interactability and opacity |
149
+ | `emptyOptionsLabel` | `string` | No | `-` | Label displayed when there are no options available |
150
+ | `end` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | End-aligned content (e.g., value, status). Replaces the deprecated detail prop. |
151
+ | `endNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the end of the inner input. Refer to diagram for location of endNode in InputStack component |
152
+ | `filterFunction` | `((options: SelectOptionList<Type, SelectOptionValue>, searchText: string) => SelectOption<SelectOptionValue>[])` | No | `-` | Custom filter function for searching options |
153
+ | `helperText` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Helper text displayed below the select |
154
+ | `hiddenSelectedOptionsLabel` | `string` | No | `-` | Label to show for showcasing count of hidden selected options |
155
+ | `hideSearchInput` | `boolean` | No | `-` | Hide the search input |
156
+ | `hideSelectAll` | `boolean` | No | `-` | Whether to hide the Select All option in multi-select mode |
157
+ | `label` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Label displayed above the control |
158
+ | `labelVariant` | `inside \| outside` | No | `'outside'` | The variant of the label. Only used when compact is not true. |
159
+ | `maxSelectedOptionsToShow` | `number` | No | `-` | Maximum number of selected options to show before truncating |
160
+ | `media` | `ReactElement` | No | `-` | Media rendered at the start of the cell (icon, avatar, image, etc). |
161
+ | `onSearch` | `((searchText: string) => void)` | No | `-` | Search text change handler |
162
+ | `open` | `boolean` | No | `-` | Controlled open state of the dropdown |
163
+ | `placeholder` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Placeholder text displayed when no option is selected |
164
+ | `ref` | `null \| (instance: SelectRef \| null) => void \| RefObject<SelectRef>` | No | `-` | - |
165
+ | `removeSelectedOptionAccessibilityLabel` | `string` | No | `-` | Accessibility label for each chip in a multi-select |
166
+ | `searchText` | `string` | No | `-` | Controlled search text value |
167
+ | `selectAllLabel` | `string` | No | `-` | Label for the Select All option in multi-select mode |
168
+ | `setOpen` | `((open: boolean \| ((open: boolean) => boolean)) => void)` | No | `-` | Callback to update the open state |
169
+ | `startNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the start of the inner input. Refer to diagram for location of startNode in InputStack component |
170
+ | `style` | `CSSProperties` | No | `-` | Inline styles for the root element |
171
+ | `styles` | `{ root?: CSSProperties; control?: CSSProperties \| undefined; controlStartNode?: CSSProperties \| undefined; controlInputNode?: CSSProperties \| undefined; controlValueNode?: CSSProperties \| undefined; controlLabelNode?: CSSProperties \| undefined; controlHelperTextNode?: CSSProperties \| undefined; controlEndNode?: CSSProperties \| undefined; controlBlendStyles?: InteractableBlendStyles \| undefined; dropdown?: CSSProperties \| undefined; option?: CSSProperties \| undefined; optionCell?: CSSProperties \| undefined; optionContent?: CSSProperties \| undefined; optionLabel?: CSSProperties \| undefined; optionDescription?: CSSProperties \| undefined; optionBlendStyles?: InteractableBlendStyles \| undefined; selectAllDivider?: CSSProperties \| undefined; emptyContentsContainer?: CSSProperties \| undefined; emptyContentsText?: CSSProperties \| undefined; optionGroup?: CSSProperties \| undefined; } \| undefined` | No | `-` | Custom styles for different parts of the select |
172
+ | `testID` | `string` | No | `-` | Test ID for the root element |
173
+ | `type` | `multi \| single` | No | `-` | Whether the select allows single or multiple selections |
174
+ | `variant` | `primary \| secondary \| positive \| negative \| foregroundMuted \| foreground` | No | `foregroundMuted` | Determines the sentiment of the input. Because we allow startContent and endContent to be custom ReactNode, the content placed inside these slots will not change colors according to the variant. You will have to add that yourself |
175
+
176
+
@@ -23,9 +23,9 @@ function Example() {
23
23
  {
24
24
  title: '$4.15',
25
25
  description: (
26
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
26
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
27
27
  &#x2197;73.37%
28
- </TextLabel2>
28
+ </Text>
29
29
  ),
30
30
  subtitle: 'ETH',
31
31
  onClick: NoopFn,
@@ -55,9 +55,9 @@ function Example() {
55
55
  {
56
56
  title: '$309.43',
57
57
  description: (
58
- <TextLabel2 as="p" color="fgPositive" numberOfLines={2}>
58
+ <Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
59
59
  &#x2197;3.37%
60
- </TextLabel2>
60
+ </Text>
61
61
  ),
62
62
  subtitle: 'Bitcoin',
63
63
  onClick: NoopFn,