@adres/mgda-ui 0.0.0-stage → 0.0.1
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/brand-knowledge.json +451 -0
- package/knowledge/accordion.md +135 -0
- package/knowledge/activity-rings.md +123 -0
- package/knowledge/alert.md +184 -0
- package/knowledge/answer-actions.md +217 -0
- package/knowledge/aspect-ratio.md +82 -0
- package/knowledge/avatar.md +158 -0
- package/knowledge/badge.md +172 -0
- package/knowledge/bar-graph.md +167 -0
- package/knowledge/bento-grid.md +115 -0
- package/knowledge/blockquote.md +153 -0
- package/knowledge/box-list.md +177 -0
- package/knowledge/bullet-list.md +128 -0
- package/knowledge/button-group.md +179 -0
- package/knowledge/button.md +231 -0
- package/knowledge/calendar.md +168 -0
- package/knowledge/card.md +321 -0
- package/knowledge/cards-nav.md +170 -0
- package/knowledge/chain-of-thought.md +164 -0
- package/knowledge/chat-container.md +135 -0
- package/knowledge/chat-message.md +224 -0
- package/knowledge/checkbox-card.md +172 -0
- package/knowledge/checkbox.md +111 -0
- package/knowledge/citations.md +241 -0
- package/knowledge/combobox.md +265 -0
- package/knowledge/countdown-pill.md +153 -0
- package/knowledge/cta.md +118 -0
- package/knowledge/data-list.md +173 -0
- package/knowledge/data-table.md +220 -0
- package/knowledge/dialog.md +249 -0
- package/knowledge/drawer.md +236 -0
- package/knowledge/dropdown-menu.md +238 -0
- package/knowledge/dropzone.md +153 -0
- package/knowledge/email-chips-input.md +161 -0
- package/knowledge/empty-state.md +106 -0
- package/knowledge/entity-header.md +166 -0
- package/knowledge/feature-grid.md +120 -0
- package/knowledge/feedback-bar.md +127 -0
- package/knowledge/footer.md +116 -0
- package/knowledge/heading.md +189 -0
- package/knowledge/hero.md +361 -0
- package/knowledge/input-button.md +187 -0
- package/knowledge/input-group.md +185 -0
- package/knowledge/input.md +256 -0
- package/knowledge/inset.md +177 -0
- package/knowledge/kpi-card.md +206 -0
- package/knowledge/list-nav.md +181 -0
- package/knowledge/logo-cloud.md +102 -0
- package/knowledge/media-gallery.md +158 -0
- package/knowledge/message-actions.md +175 -0
- package/knowledge/nav-sidebar.md +225 -0
- package/knowledge/number-stepper.md +159 -0
- package/knowledge/page-header.md +109 -0
- package/knowledge/pagination.md +225 -0
- package/knowledge/popover.md +159 -0
- package/knowledge/pricing.md +132 -0
- package/knowledge/progress.md +156 -0
- package/knowledge/prompt-input.md +337 -0
- package/knowledge/prompt-suggestions.md +168 -0
- package/knowledge/quota-bar.md +160 -0
- package/knowledge/quote.md +116 -0
- package/knowledge/radio-card.md +172 -0
- package/knowledge/radio-group.md +135 -0
- package/knowledge/reasoning.md +142 -0
- package/knowledge/search.md +131 -0
- package/knowledge/section-nav.md +162 -0
- package/knowledge/segmented-control.md +181 -0
- package/knowledge/select-button.md +205 -0
- package/knowledge/select.md +210 -0
- package/knowledge/separator.md +75 -0
- package/knowledge/shimmer-text.md +140 -0
- package/knowledge/sidebar.md +227 -0
- package/knowledge/skeleton.md +142 -0
- package/knowledge/slider.md +133 -0
- package/knowledge/slideshow.md +159 -0
- package/knowledge/source.md +156 -0
- package/knowledge/spinner.md +120 -0
- package/knowledge/stat-strip.md +128 -0
- package/knowledge/stats.md +117 -0
- package/knowledge/step-indicator.md +157 -0
- package/knowledge/switch.md +88 -0
- package/knowledge/table.md +190 -0
- package/knowledge/tabs.md +169 -0
- package/knowledge/testimonials.md +115 -0
- package/knowledge/text-link.md +192 -0
- package/knowledge/text.md +194 -0
- package/knowledge/thinking-bar.md +115 -0
- package/knowledge/thinking-steps.md +140 -0
- package/knowledge/toaster.md +127 -0
- package/knowledge/toggle.md +113 -0
- package/knowledge/tool-call-card.md +241 -0
- package/knowledge/tooltip.md +120 -0
- package/knowledge/top-nav.md +138 -0
- package/knowledge.json +19854 -0
- package/package.json +94 -4
- package/src/components/accordion.stories.tsx +46 -0
- package/src/components/accordion.tsx +74 -0
- package/src/components/activity-rings.stories.tsx +73 -0
- package/src/components/activity-rings.tsx +121 -0
- package/src/components/alert.stories.tsx +43 -0
- package/src/components/alert.tsx +132 -0
- package/src/components/answer-actions.stories.tsx +54 -0
- package/src/components/answer-actions.test.tsx +37 -0
- package/src/components/answer-actions.tsx +313 -0
- package/src/components/aspect-ratio.stories.tsx +32 -0
- package/src/components/aspect-ratio.tsx +5 -0
- package/src/components/avatar.stories.tsx +40 -0
- package/src/components/avatar.tsx +154 -0
- package/src/components/badge.stories.tsx +27 -0
- package/src/components/badge.tsx +63 -0
- package/src/components/bar-graph.stories.tsx +28 -0
- package/src/components/bar-graph.tsx +204 -0
- package/src/components/bento-grid.stories.tsx +23 -0
- package/src/components/bento-grid.tsx +67 -0
- package/src/components/blockquote.stories.tsx +28 -0
- package/src/components/blockquote.tsx +88 -0
- package/src/components/box-list.stories.tsx +25 -0
- package/src/components/box-list.tsx +108 -0
- package/src/components/bullet-list.stories.tsx +22 -0
- package/src/components/bullet-list.tsx +101 -0
- package/src/components/button-group.stories.tsx +31 -0
- package/src/components/button-group.tsx +156 -0
- package/src/components/button.stories.tsx +66 -0
- package/src/components/button.test.ts +17 -0
- package/src/components/button.tsx +139 -0
- package/src/components/calendar.stories.tsx +25 -0
- package/src/components/calendar.tsx +367 -0
- package/src/components/card.stories.tsx +44 -0
- package/src/components/card.tsx +392 -0
- package/src/components/cards-nav.stories.tsx +35 -0
- package/src/components/cards-nav.tsx +115 -0
- package/src/components/chain-of-thought.stories.tsx +67 -0
- package/src/components/chain-of-thought.test.tsx +50 -0
- package/src/components/chain-of-thought.tsx +170 -0
- package/src/components/chat-container.stories.tsx +47 -0
- package/src/components/chat-container.test.tsx +49 -0
- package/src/components/chat-container.tsx +222 -0
- package/src/components/chat-message.stories.tsx +52 -0
- package/src/components/chat-message.test.tsx +36 -0
- package/src/components/chat-message.tsx +163 -0
- package/src/components/checkbox-card.stories.tsx +27 -0
- package/src/components/checkbox-card.tsx +200 -0
- package/src/components/checkbox.stories.tsx +26 -0
- package/src/components/checkbox.tsx +61 -0
- package/src/components/citations.stories.tsx +64 -0
- package/src/components/citations.test.tsx +61 -0
- package/src/components/citations.tsx +220 -0
- package/src/components/combobox.stories.tsx +184 -0
- package/src/components/combobox.test.tsx +82 -0
- package/src/components/combobox.tsx +407 -0
- package/src/components/countdown-pill.stories.tsx +24 -0
- package/src/components/countdown-pill.tsx +129 -0
- package/src/components/cta.stories.tsx +29 -0
- package/src/components/cta.tsx +52 -0
- package/src/components/data-list.stories.tsx +50 -0
- package/src/components/data-list.test.tsx +35 -0
- package/src/components/data-list.tsx +181 -0
- package/src/components/data-table.stories.tsx +29 -0
- package/src/components/data-table.tsx +200 -0
- package/src/components/dialog.stories.tsx +42 -0
- package/src/components/dialog.tsx +200 -0
- package/src/components/drawer.stories.tsx +48 -0
- package/src/components/drawer.tsx +385 -0
- package/src/components/dropdown-menu.stories.tsx +41 -0
- package/src/components/dropdown-menu.tsx +252 -0
- package/src/components/dropzone.stories.tsx +19 -0
- package/src/components/dropzone.tsx +250 -0
- package/src/components/email-chips-input.stories.tsx +135 -0
- package/src/components/email-chips-input.tsx +210 -0
- package/src/components/empty-state.stories.tsx +22 -0
- package/src/components/empty-state.tsx +35 -0
- package/src/components/entity-header.stories.tsx +43 -0
- package/src/components/entity-header.test.tsx +35 -0
- package/src/components/entity-header.tsx +92 -0
- package/src/components/feature-grid.stories.tsx +25 -0
- package/src/components/feature-grid.tsx +87 -0
- package/src/components/feedback-bar.stories.tsx +25 -0
- package/src/components/feedback-bar.test.tsx +24 -0
- package/src/components/feedback-bar.tsx +62 -0
- package/src/components/footer.stories.tsx +23 -0
- package/src/components/footer.tsx +78 -0
- package/src/components/heading.stories.tsx +45 -0
- package/src/components/heading.test.tsx +22 -0
- package/src/components/heading.tsx +77 -0
- package/src/components/hero.stories.tsx +38 -0
- package/src/components/hero.tsx +498 -0
- package/src/components/input-button.stories.tsx +19 -0
- package/src/components/input-button.tsx +112 -0
- package/src/components/input-group.stories.tsx +38 -0
- package/src/components/input-group.tsx +157 -0
- package/src/components/input.stories.tsx +31 -0
- package/src/components/input.tsx +284 -0
- package/src/components/inset.stories.tsx +29 -0
- package/src/components/inset.tsx +70 -0
- package/src/components/kpi-card.stories.tsx +29 -0
- package/src/components/kpi-card.tsx +284 -0
- package/src/components/list-nav.stories.tsx +22 -0
- package/src/components/list-nav.tsx +145 -0
- package/src/components/logo-cloud.stories.tsx +23 -0
- package/src/components/logo-cloud.tsx +42 -0
- package/src/components/media-gallery.stories.tsx +25 -0
- package/src/components/media-gallery.tsx +347 -0
- package/src/components/message-actions.stories.tsx +45 -0
- package/src/components/message-actions.test.tsx +32 -0
- package/src/components/message-actions.tsx +119 -0
- package/src/components/nav-sidebar.stories.tsx +58 -0
- package/src/components/nav-sidebar.test.tsx +54 -0
- package/src/components/nav-sidebar.tsx +462 -0
- package/src/components/number-stepper.stories.tsx +19 -0
- package/src/components/number-stepper.tsx +158 -0
- package/src/components/page-header.stories.tsx +25 -0
- package/src/components/page-header.tsx +64 -0
- package/src/components/pagination.stories.tsx +110 -0
- package/src/components/pagination.test.tsx +46 -0
- package/src/components/pagination.tsx +144 -0
- package/src/components/popover.stories.tsx +26 -0
- package/src/components/popover.tsx +62 -0
- package/src/components/pricing.stories.tsx +42 -0
- package/src/components/pricing.tsx +130 -0
- package/src/components/progress.stories.tsx +22 -0
- package/src/components/progress.tsx +189 -0
- package/src/components/prompt-input.stories.tsx +62 -0
- package/src/components/prompt-input.test.tsx +106 -0
- package/src/components/prompt-input.tsx +343 -0
- package/src/components/prompt-suggestions.stories.tsx +53 -0
- package/src/components/prompt-suggestions.test.tsx +37 -0
- package/src/components/prompt-suggestions.tsx +122 -0
- package/src/components/quota-bar.stories.tsx +19 -0
- package/src/components/quota-bar.tsx +191 -0
- package/src/components/quote.stories.tsx +18 -0
- package/src/components/quote.tsx +43 -0
- package/src/components/radio-card.stories.tsx +27 -0
- package/src/components/radio-card.tsx +225 -0
- package/src/components/radio-group.stories.tsx +32 -0
- package/src/components/radio-group.tsx +68 -0
- package/src/components/reasoning.stories.tsx +50 -0
- package/src/components/reasoning.test.tsx +48 -0
- package/src/components/reasoning.tsx +143 -0
- package/src/components/search.stories.tsx +18 -0
- package/src/components/search.tsx +133 -0
- package/src/components/section-nav.stories.tsx +59 -0
- package/src/components/section-nav.test.tsx +36 -0
- package/src/components/section-nav.tsx +146 -0
- package/src/components/segmented-control.stories.tsx +22 -0
- package/src/components/segmented-control.tsx +301 -0
- package/src/components/select-button.stories.tsx +27 -0
- package/src/components/select-button.tsx +174 -0
- package/src/components/select.stories.tsx +27 -0
- package/src/components/select.tsx +198 -0
- package/src/components/separator.stories.tsx +22 -0
- package/src/components/separator.tsx +23 -0
- package/src/components/shimmer-text.stories.tsx +23 -0
- package/src/components/shimmer-text.test.tsx +35 -0
- package/src/components/shimmer-text.tsx +43 -0
- package/src/components/sidebar.stories.tsx +25 -0
- package/src/components/sidebar.tsx +234 -0
- package/src/components/skeleton.stories.tsx +22 -0
- package/src/components/skeleton.tsx +96 -0
- package/src/components/slider.stories.tsx +20 -0
- package/src/components/slider.tsx +176 -0
- package/src/components/slideshow.stories.tsx +30 -0
- package/src/components/slideshow.tsx +291 -0
- package/src/components/source.stories.tsx +32 -0
- package/src/components/source.test.tsx +40 -0
- package/src/components/source.tsx +161 -0
- package/src/components/spinner.stories.tsx +19 -0
- package/src/components/spinner.tsx +76 -0
- package/src/components/stat-strip.stories.tsx +36 -0
- package/src/components/stat-strip.test.tsx +25 -0
- package/src/components/stat-strip.tsx +85 -0
- package/src/components/stats.stories.tsx +24 -0
- package/src/components/stats.tsx +83 -0
- package/src/components/step-indicator.stories.tsx +18 -0
- package/src/components/step-indicator.test.tsx +18 -0
- package/src/components/step-indicator.tsx +286 -0
- package/src/components/switch.stories.tsx +26 -0
- package/src/components/switch.tsx +32 -0
- package/src/components/table.stories.tsx +38 -0
- package/src/components/table.tsx +220 -0
- package/src/components/tabs.stories.tsx +25 -0
- package/src/components/tabs.tsx +276 -0
- package/src/components/testimonials.stories.tsx +22 -0
- package/src/components/testimonials.tsx +109 -0
- package/src/components/text-link.stories.tsx +47 -0
- package/src/components/text-link.test.tsx +18 -0
- package/src/components/text-link.tsx +88 -0
- package/src/components/text.stories.tsx +49 -0
- package/src/components/text.tsx +105 -0
- package/src/components/thinking-bar.stories.tsx +19 -0
- package/src/components/thinking-bar.test.tsx +27 -0
- package/src/components/thinking-bar.tsx +64 -0
- package/src/components/thinking-steps.stories.tsx +44 -0
- package/src/components/thinking-steps.test.tsx +42 -0
- package/src/components/thinking-steps.tsx +92 -0
- package/src/components/toaster.stories.tsx +80 -0
- package/src/components/toaster.tsx +36 -0
- package/src/components/toggle.stories.tsx +21 -0
- package/src/components/toggle.tsx +103 -0
- package/src/components/tool-call-card.stories.tsx +97 -0
- package/src/components/tool-call-card.test.tsx +88 -0
- package/src/components/tool-call-card.tsx +231 -0
- package/src/components/tooltip.stories.tsx +25 -0
- package/src/components/tooltip.tsx +43 -0
- package/src/components/top-nav.stories.tsx +20 -0
- package/src/components/top-nav.tsx +76 -0
- package/src/docs/Colors.stories.tsx +192 -0
- package/src/docs/GettingStarted.mdx +72 -0
- package/src/docs/Mcp.mdx +52 -0
- package/src/docs/Typography.stories.tsx +114 -0
- package/src/hooks/use-in-view.ts +32 -0
- package/src/hooks/use-reduced-motion.ts +26 -0
- package/src/index.ts +343 -0
- package/src/lib/cn.test.ts +67 -0
- package/src/lib/cn.ts +81 -0
- package/src/lib/motion.ts +109 -0
- package/src/lib/prefix-utilities.test.ts +56 -0
- package/src/lib/prefix-utilities.ts +50 -0
- package/src/styles/base.css +489 -0
- package/src/styles/motion.css +69 -0
- package/src/styles/overrides.css +44 -0
- package/src/styles/typography.css +173 -0
- package/src/theme/theme.css +391 -0
- package/src/theme/tokens.ts +29 -0
- package/src/theme/types.ts +26 -0
- package/README.md +0 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: blockquote
|
|
6
|
+
sourceFile: packages/design-system/src/components/blockquote.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-core-primitives
|
|
9
|
+
categoryFromBarrel: web-app-core-primitives
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: Blockquote
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "ForwardRefExoticComponent<BlockquoteProps & RefAttributes<HTMLQuoteElement>>"
|
|
16
|
+
- name: BlockquoteCaption
|
|
17
|
+
kind: component
|
|
18
|
+
typeText: "ForwardRefExoticComponent<BlockquoteCaptionProps & RefAttributes<HTMLElement>>"
|
|
19
|
+
- name: BlockquoteCaptionProps
|
|
20
|
+
kind: type
|
|
21
|
+
- name: BlockquoteColor
|
|
22
|
+
kind: type
|
|
23
|
+
- name: BlockquoteFigure
|
|
24
|
+
kind: component
|
|
25
|
+
typeText: "ForwardRefExoticComponent<BlockquoteFigureProps & RefAttributes<HTMLElement>>"
|
|
26
|
+
- name: BlockquoteFigureProps
|
|
27
|
+
kind: type
|
|
28
|
+
- name: BlockquoteProps
|
|
29
|
+
kind: type
|
|
30
|
+
- name: BlockquoteSize
|
|
31
|
+
kind: type
|
|
32
|
+
- name: blockquoteVariants
|
|
33
|
+
kind: variants
|
|
34
|
+
typeText: "(props?: (ConfigVariants<{ size: { sm: string; md: string; lg: string; xl: string; }; color: { primary: string; neutral: string; }; }> & ClassProp) | undefined) => string"
|
|
35
|
+
primaryExport: Blockquote
|
|
36
|
+
subcomponents:
|
|
37
|
+
- BlockquoteCaption
|
|
38
|
+
- BlockquoteFigure
|
|
39
|
+
props:
|
|
40
|
+
Blockquote:
|
|
41
|
+
- name: color
|
|
42
|
+
type: "\"neutral\" | \"primary\""
|
|
43
|
+
required: false
|
|
44
|
+
declaredIn: self
|
|
45
|
+
variantKey: true
|
|
46
|
+
- name: size
|
|
47
|
+
type: "\"lg\" | \"md\" | \"sm\" | \"xl\""
|
|
48
|
+
required: false
|
|
49
|
+
declaredIn: self
|
|
50
|
+
variantKey: true
|
|
51
|
+
extendsProps:
|
|
52
|
+
- "Omit<React.BlockquoteHTMLAttributes<HTMLQuoteElement>, \"color\">"
|
|
53
|
+
- "VariantProps<typeof blockquoteVariants>"
|
|
54
|
+
variants:
|
|
55
|
+
size:
|
|
56
|
+
kind: enum
|
|
57
|
+
options:
|
|
58
|
+
- sm
|
|
59
|
+
- md
|
|
60
|
+
- lg
|
|
61
|
+
- xl
|
|
62
|
+
default: md
|
|
63
|
+
on: Blockquote
|
|
64
|
+
color:
|
|
65
|
+
kind: enum
|
|
66
|
+
options:
|
|
67
|
+
- primary
|
|
68
|
+
- neutral
|
|
69
|
+
default: primary
|
|
70
|
+
on: Blockquote
|
|
71
|
+
variantSource: cva
|
|
72
|
+
compoundVariants: []
|
|
73
|
+
sizeMaps: []
|
|
74
|
+
dataSlots: []
|
|
75
|
+
dependsOn:
|
|
76
|
+
internal: []
|
|
77
|
+
lib:
|
|
78
|
+
- cn
|
|
79
|
+
hooks: []
|
|
80
|
+
external:
|
|
81
|
+
- class-variance-authority
|
|
82
|
+
- react
|
|
83
|
+
contexts: []
|
|
84
|
+
stories:
|
|
85
|
+
- exportName: Default
|
|
86
|
+
id: components-blockquote--default
|
|
87
|
+
- exportName: WithCaption
|
|
88
|
+
id: components-blockquote--with-caption
|
|
89
|
+
storybookTitle: Components/Blockquote
|
|
90
|
+
docsId: components-blockquote--documentation
|
|
91
|
+
argTypeOptions: {}
|
|
92
|
+
resolvedCleanly: true
|
|
93
|
+
contractHash: c13962b650ce
|
|
94
|
+
factsHash: "6d095004c0a7"
|
|
95
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
96
|
+
status: stable
|
|
97
|
+
summary: "A block-level extended quotation, with an optional figure/caption pairing for attribution."
|
|
98
|
+
useWhen:
|
|
99
|
+
- "quoting a longer passage as its own block, especially editorial or testimonial content"
|
|
100
|
+
- "attributing the quote to a source (pair with BlockquoteFigure and BlockquoteCaption)"
|
|
101
|
+
useInstead:
|
|
102
|
+
- id: quote
|
|
103
|
+
when: "the quotation is short and sits inline within a sentence, not as its own block"
|
|
104
|
+
- id: text
|
|
105
|
+
when: "the content is not actually a quotation - Text carries no semantic blockquote meaning"
|
|
106
|
+
related:
|
|
107
|
+
- quote
|
|
108
|
+
- text
|
|
109
|
+
a11y:
|
|
110
|
+
notes:
|
|
111
|
+
- "Renders a real <blockquote> element, so assistive tech recognizes it as a quotation without extra ARIA."
|
|
112
|
+
- "BlockquoteCaption renders <figcaption>, which is only valid HTML as a child of a <figure> - always wrap Blockquote and BlockquoteCaption in BlockquoteFigure when using a caption, never render BlockquoteCaption on its own."
|
|
113
|
+
radixHandles: false
|
|
114
|
+
pitfalls:
|
|
115
|
+
- "BlockquoteCaption is invalid HTML outside a <figure> - use BlockquoteFigure as the wrapper any time a caption is present, not a plain div."
|
|
116
|
+
- "color's neutral/primary options only tint the left border accent - they say nothing about the quote's semantic importance and do not affect the text color itself."
|
|
117
|
+
- "size=\"xl\" does not follow the same t-body-* type token as sm/md/lg - it is a one-off text-xl override for hero or editorial quotes, so it will not track a future change to the t-body-lg token the way the other three sizes will."
|
|
118
|
+
canonicalSnippet: |
|
|
119
|
+
import { Blockquote, BlockquoteCaption, BlockquoteFigure } from "@adres/mgda-ui"
|
|
120
|
+
|
|
121
|
+
<BlockquoteFigure>
|
|
122
|
+
<Blockquote size="lg">
|
|
123
|
+
Great design is as little design as possible.
|
|
124
|
+
</Blockquote>
|
|
125
|
+
<BlockquoteCaption>Dieter Rams</BlockquoteCaption>
|
|
126
|
+
</BlockquoteFigure>
|
|
127
|
+
reviewedAt: 2026-08-31
|
|
128
|
+
reviewedAgainstContractHash: c13962b650ce
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
|
|
133
|
+
`Blockquote` renders a real `<blockquote>` for a longer, standalone quotation
|
|
134
|
+
- editorial pull-quotes, testimonials, cited passages. For a short quotation
|
|
135
|
+
that sits inline within a sentence, reach for `Quote` instead; for content
|
|
136
|
+
that is not actually a quotation, reach for `Text`.
|
|
137
|
+
|
|
138
|
+
`color` only tints the left border accent (`primary` or `neutral`); it does
|
|
139
|
+
not change the quote's text color or imply semantic importance. `size` scales
|
|
140
|
+
the body type, with `xl` as a one-off larger override for hero or editorial
|
|
141
|
+
use rather than following the normal `t-body-*` ramp the other three sizes
|
|
142
|
+
use.
|
|
143
|
+
|
|
144
|
+
Pair with `BlockquoteFigure` and `BlockquoteCaption` for attribution - the
|
|
145
|
+
caption renders `<figcaption>`, which is only valid HTML inside a `<figure>`.
|
|
146
|
+
|
|
147
|
+
## Anatomy
|
|
148
|
+
|
|
149
|
+
| Part | Role |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| `Blockquote` | The quotation itself. Renders `<blockquote>`. |
|
|
152
|
+
| `BlockquoteFigure` | Structural `<figure>` wrapper, required around `Blockquote` and `BlockquoteCaption` whenever a caption is used. |
|
|
153
|
+
| `BlockquoteCaption` | The attribution. Renders `<figcaption>` - invalid HTML outside a `<figure>`. |
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: box-list
|
|
6
|
+
sourceFile: packages/design-system/src/components/box-list.tsx
|
|
7
|
+
client: false
|
|
8
|
+
category: web-app-layout-navigation
|
|
9
|
+
categoryFromBarrel: web-app-layout-navigation
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: BoxList
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "({ items, columns, size, textSize, vertical, bullet, check, numerical, muted, className, ...props }: BoxListProps) => Element"
|
|
16
|
+
- name: BoxListItem
|
|
17
|
+
kind: type
|
|
18
|
+
- name: BoxListProps
|
|
19
|
+
kind: type
|
|
20
|
+
- name: BoxListSize
|
|
21
|
+
kind: type
|
|
22
|
+
primaryExport: BoxList
|
|
23
|
+
subcomponents: []
|
|
24
|
+
props:
|
|
25
|
+
BoxList:
|
|
26
|
+
- name: bullet
|
|
27
|
+
type: boolean
|
|
28
|
+
required: false
|
|
29
|
+
declaredIn: self
|
|
30
|
+
doc: "Show a leading bullet dot before each item's title."
|
|
31
|
+
- name: check
|
|
32
|
+
type: boolean
|
|
33
|
+
required: false
|
|
34
|
+
declaredIn: self
|
|
35
|
+
doc: "Show a leading Check icon before each item's title - for \"included\" / affirmative sets. Takes precedence over `bullet` when both are set."
|
|
36
|
+
- name: columns
|
|
37
|
+
type: "1 | 2 | 3 | 4"
|
|
38
|
+
required: false
|
|
39
|
+
declaredIn: self
|
|
40
|
+
doc: "Columns at desktop (1-4). Default 3. Ignored when `vertical`."
|
|
41
|
+
- name: items
|
|
42
|
+
type: "BoxListItem[]"
|
|
43
|
+
required: true
|
|
44
|
+
declaredIn: self
|
|
45
|
+
- name: muted
|
|
46
|
+
type: boolean
|
|
47
|
+
required: false
|
|
48
|
+
declaredIn: self
|
|
49
|
+
doc: "Sit each item on the muted surface (`bg-muted`) instead of the default card surface - a softer, lower-contrast fill for secondary lists."
|
|
50
|
+
- name: numerical
|
|
51
|
+
type: boolean
|
|
52
|
+
required: false
|
|
53
|
+
declaredIn: self
|
|
54
|
+
doc: "Show a two-digit ordinal (01, 02, ...) as a t-overline eyebrow above each item. Takes precedence over `check` and `bullet` when several are set."
|
|
55
|
+
- name: size
|
|
56
|
+
type: BoxListSize
|
|
57
|
+
required: false
|
|
58
|
+
declaredIn: self
|
|
59
|
+
doc: "Box padding. Default \"lg\"."
|
|
60
|
+
- name: textSize
|
|
61
|
+
type: BoxListSize
|
|
62
|
+
required: false
|
|
63
|
+
declaredIn: self
|
|
64
|
+
doc: "Type scale for the title + description. Default \"md\"."
|
|
65
|
+
- name: vertical
|
|
66
|
+
type: boolean
|
|
67
|
+
required: false
|
|
68
|
+
declaredIn: self
|
|
69
|
+
doc: "Stack items in a single vertical column instead of a grid. Overrides `columns`."
|
|
70
|
+
extendsProps:
|
|
71
|
+
- "React.HTMLAttributes<HTMLDivElement>"
|
|
72
|
+
variants:
|
|
73
|
+
size:
|
|
74
|
+
kind: enum
|
|
75
|
+
options:
|
|
76
|
+
- sm
|
|
77
|
+
- md
|
|
78
|
+
- lg
|
|
79
|
+
default: lg
|
|
80
|
+
on: BoxList
|
|
81
|
+
textSize:
|
|
82
|
+
kind: enum
|
|
83
|
+
options:
|
|
84
|
+
- sm
|
|
85
|
+
- md
|
|
86
|
+
- lg
|
|
87
|
+
default: md
|
|
88
|
+
on: BoxList
|
|
89
|
+
variantSource: prop-union
|
|
90
|
+
compoundVariants: []
|
|
91
|
+
sizeMaps:
|
|
92
|
+
- COLUMNS
|
|
93
|
+
- SIZE
|
|
94
|
+
- TEXT
|
|
95
|
+
dataSlots: []
|
|
96
|
+
dependsOn:
|
|
97
|
+
internal: []
|
|
98
|
+
lib:
|
|
99
|
+
- cn
|
|
100
|
+
hooks: []
|
|
101
|
+
external:
|
|
102
|
+
- lucide-react
|
|
103
|
+
- react
|
|
104
|
+
contexts: []
|
|
105
|
+
stories:
|
|
106
|
+
- exportName: Default
|
|
107
|
+
id: components-boxlist--default
|
|
108
|
+
- exportName: WithChecks
|
|
109
|
+
id: components-boxlist--with-checks
|
|
110
|
+
storybookTitle: Components/BoxList
|
|
111
|
+
docsId: components-boxlist--documentation
|
|
112
|
+
argTypeOptions: {}
|
|
113
|
+
resolvedCleanly: true
|
|
114
|
+
contractHash: da6243592924
|
|
115
|
+
factsHash: "961259e83400"
|
|
116
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
117
|
+
status: stable
|
|
118
|
+
summary: "A responsive grid of bordered box cards, each a title with an optional supporting line - features, services, terms, or options."
|
|
119
|
+
useWhen:
|
|
120
|
+
- "presenting a set of features, services, terms, or options as bordered cards without hand-rolling the card + grid each time"
|
|
121
|
+
- "an affirmative \"what's included\" list (turn on check) or an ordered sequence (turn on numerical)"
|
|
122
|
+
useInstead:
|
|
123
|
+
- id: bullet-list
|
|
124
|
+
when: "the items are a short prose-adjacent list with no need for a bordered box or grid"
|
|
125
|
+
- id: cards-nav
|
|
126
|
+
when: "each box should actually navigate somewhere - BoxList items are static, not links"
|
|
127
|
+
- id: feature-grid
|
|
128
|
+
when: "each item needs its own icon plus richer marketing copy, not just a title/description pair"
|
|
129
|
+
related:
|
|
130
|
+
- bullet-list
|
|
131
|
+
- feature-grid
|
|
132
|
+
composesWith: []
|
|
133
|
+
tokens:
|
|
134
|
+
- "--card"
|
|
135
|
+
- "--muted"
|
|
136
|
+
- "--foreground"
|
|
137
|
+
- "--foreground-strong"
|
|
138
|
+
- "--muted-foreground"
|
|
139
|
+
- "--primary"
|
|
140
|
+
a11y:
|
|
141
|
+
notes:
|
|
142
|
+
- "BoxList is a server component (no \"use client\") - it renders plain divs with no interactivity, so it drops into a server component tree with no extra opt-in."
|
|
143
|
+
- "check and numerical icons/ordinals are decorative and rendered without their own accessible name; the item's title or description is what a screen reader announces."
|
|
144
|
+
requiredProps:
|
|
145
|
+
- "each item needs at least title or description - both may be set, but at least one carries the visible content"
|
|
146
|
+
keyboard: []
|
|
147
|
+
radixHandles: false
|
|
148
|
+
pitfalls:
|
|
149
|
+
- "marker precedence is numerical, then check, then bullet - setting more than one only shows the highest-precedence marker, the others are silently ignored, not stacked."
|
|
150
|
+
- "vertical overrides columns entirely - setting both stacks items in one column regardless of the columns value, since vertical switches the container from grid to flex-col."
|
|
151
|
+
- "an item with only description (no title) renders that text at the title type scale, not the description scale - BoxList treats the first present field as the item's headline."
|
|
152
|
+
canonicalSnippet: |
|
|
153
|
+
import { BoxList, type BoxListItem } from "@adres/mgda-ui"
|
|
154
|
+
|
|
155
|
+
const items: BoxListItem[] = [
|
|
156
|
+
{ title: "Unlimited projects", description: "No caps on workspaces or seats." },
|
|
157
|
+
{ title: "Priority support", description: "Same-day response on business plans." },
|
|
158
|
+
{ title: "Custom domains", description: "Point your own domain at any project." },
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
<BoxList items={items} check columns={3} />
|
|
162
|
+
reviewedAt: 2026-08-31
|
|
163
|
+
reviewedAgainstContractHash: da6243592924
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Usage
|
|
167
|
+
|
|
168
|
+
BoxList turns a flat array of `{ title, description }` pairs into a
|
|
169
|
+
responsive grid of bordered cards, so a features/services/terms section
|
|
170
|
+
doesn't need its own hand-rolled grid + card markup. `vertical` collapses it
|
|
171
|
+
to a single column regardless of `columns`, useful on narrow layouts or when
|
|
172
|
+
the content itself reads better stacked.
|
|
173
|
+
|
|
174
|
+
Choose at most one marker style: `numerical` (a "01, 02, ..." eyebrow, for
|
|
175
|
+
ordered sequences), `check` (an affirmative "included" icon), or `bullet` (a
|
|
176
|
+
plain dot for an unordered set). They take precedence in that order - setting
|
|
177
|
+
more than one shows only the highest-precedence marker.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: bullet-list
|
|
6
|
+
sourceFile: packages/design-system/src/components/bullet-list.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-layout-navigation
|
|
9
|
+
categoryFromBarrel: web-app-layout-navigation
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: BulletList
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "ForwardRefExoticComponent<BulletListProps & RefAttributes<HTMLUListElement>>"
|
|
16
|
+
- name: BulletListItem
|
|
17
|
+
kind: component
|
|
18
|
+
typeText: "ForwardRefExoticComponent<BulletListItemProps & RefAttributes<HTMLLIElement>>"
|
|
19
|
+
- name: BulletListItemProps
|
|
20
|
+
kind: type
|
|
21
|
+
- name: BulletListProps
|
|
22
|
+
kind: type
|
|
23
|
+
- name: BulletListSize
|
|
24
|
+
kind: type
|
|
25
|
+
primaryExport: BulletList
|
|
26
|
+
subcomponents:
|
|
27
|
+
- BulletListItem
|
|
28
|
+
props:
|
|
29
|
+
BulletList:
|
|
30
|
+
- name: size
|
|
31
|
+
type: BulletListSize
|
|
32
|
+
required: false
|
|
33
|
+
declaredIn: self
|
|
34
|
+
extendsProps:
|
|
35
|
+
- "React.HTMLAttributes<HTMLUListElement>"
|
|
36
|
+
variants:
|
|
37
|
+
size:
|
|
38
|
+
kind: enum
|
|
39
|
+
options:
|
|
40
|
+
- sm
|
|
41
|
+
- md
|
|
42
|
+
- lg
|
|
43
|
+
default: md
|
|
44
|
+
on: BulletList
|
|
45
|
+
variantSource: prop-union
|
|
46
|
+
compoundVariants: []
|
|
47
|
+
sizeMaps:
|
|
48
|
+
- BULLET_CLASS
|
|
49
|
+
- LIST_GAP_CLASS
|
|
50
|
+
- ROW_GAP_CLASS
|
|
51
|
+
- TEXT_CLASS
|
|
52
|
+
dataSlots: []
|
|
53
|
+
dependsOn:
|
|
54
|
+
internal: []
|
|
55
|
+
lib:
|
|
56
|
+
- cn
|
|
57
|
+
hooks: []
|
|
58
|
+
external:
|
|
59
|
+
- react
|
|
60
|
+
contexts:
|
|
61
|
+
- name: BulletListContext
|
|
62
|
+
type: BulletListContextValue
|
|
63
|
+
default: null
|
|
64
|
+
stories:
|
|
65
|
+
- exportName: Default
|
|
66
|
+
id: components-bulletlist--default
|
|
67
|
+
storybookTitle: Components/BulletList
|
|
68
|
+
docsId: components-bulletlist--documentation
|
|
69
|
+
argTypeOptions: {}
|
|
70
|
+
resolvedCleanly: true
|
|
71
|
+
contractHash: "96c5ce6fa5fb"
|
|
72
|
+
factsHash: "5b52ebd7a9e8"
|
|
73
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
74
|
+
status: stable
|
|
75
|
+
summary: "A bulleted list of short related items - goals, features, qualities - with body-text rhythm and a small dot marker."
|
|
76
|
+
useWhen:
|
|
77
|
+
- "a short unordered list of related items (features, benefits, requirements) where the surrounding heading already sets the context"
|
|
78
|
+
- "prose-adjacent content that should read as body text with bullets, not a card or box grid"
|
|
79
|
+
useInstead:
|
|
80
|
+
- id: box-list
|
|
81
|
+
when: "each item deserves its own bordered box, a title + description pair, or a grid layout"
|
|
82
|
+
- id: data-list
|
|
83
|
+
when: "each row is a label/value pair rather than a single line of text"
|
|
84
|
+
related:
|
|
85
|
+
- box-list
|
|
86
|
+
composesWith: []
|
|
87
|
+
tokens:
|
|
88
|
+
- "--foreground"
|
|
89
|
+
- "--foreground-strong"
|
|
90
|
+
a11y:
|
|
91
|
+
notes:
|
|
92
|
+
- "Renders a real <ul>/<li> pair, so list semantics (list role, item count) are announced by screen readers with no extra markup."
|
|
93
|
+
- "The bullet dot is aria-hidden - the accessible content of each row is exactly the children text, not a rendered \"•\"."
|
|
94
|
+
requiredProps: []
|
|
95
|
+
keyboard: []
|
|
96
|
+
radixHandles: false
|
|
97
|
+
pitfalls:
|
|
98
|
+
- "size only changes text scale, bullet diameter, and spacing - it does not add or remove structure, so mixing sizes across BulletLists on the same page is a purely visual choice with no other effect."
|
|
99
|
+
- "BulletListItem takes plain children, not a title/description pair - reach for BoxList when an item needs two lines."
|
|
100
|
+
canonicalSnippet: |
|
|
101
|
+
import { BulletList, BulletListItem } from "@adres/mgda-ui"
|
|
102
|
+
|
|
103
|
+
<BulletList size="md">
|
|
104
|
+
<BulletListItem>Works across every brand theme</BulletListItem>
|
|
105
|
+
<BulletListItem>WCAG 2.1 AA accessible by default</BulletListItem>
|
|
106
|
+
<BulletListItem>No hardcoded colors anywhere in the component tree</BulletListItem>
|
|
107
|
+
</BulletList>
|
|
108
|
+
reviewedAt: 2026-08-31
|
|
109
|
+
reviewedAgainstContractHash: "96c5ce6fa5fb"
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Usage
|
|
113
|
+
|
|
114
|
+
BulletList is a plain content list, not a navigation control - despite living
|
|
115
|
+
in the `Layout & Navigation` barrel section alongside `Sidebar`/`ListNav`, it
|
|
116
|
+
renders no links and carries no active/selected state. Reach for it when
|
|
117
|
+
prose calls for a short bulleted list (a feature set, a set of qualities) and
|
|
118
|
+
the default browser bullet doesn't match the type system.
|
|
119
|
+
|
|
120
|
+
`size` cascades from `BulletList` to every `BulletListItem` via context,
|
|
121
|
+
scaling text, bullet diameter, and row/list spacing together so the three
|
|
122
|
+
stay proportional.
|
|
123
|
+
|
|
124
|
+
## Anatomy
|
|
125
|
+
|
|
126
|
+
- **BulletList** - the `<ul>` wrapper; sets `size` for its items via context.
|
|
127
|
+
- **BulletListItem** - one `<li>`: a small foreground-strong dot marker
|
|
128
|
+
followed by plain children.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
# >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
|
|
3
|
+
derived:
|
|
4
|
+
schemaVersion: 1
|
|
5
|
+
id: button-group
|
|
6
|
+
sourceFile: packages/design-system/src/components/button-group.tsx
|
|
7
|
+
client: true
|
|
8
|
+
category: web-app-core-primitives
|
|
9
|
+
categoryFromBarrel: web-app-core-primitives
|
|
10
|
+
barrelExported: true
|
|
11
|
+
importPath: "@adres/mgda-ui"
|
|
12
|
+
exports:
|
|
13
|
+
- name: ButtonGroup
|
|
14
|
+
kind: component
|
|
15
|
+
typeText: "ForwardRefExoticComponent<ButtonGroupProps & RefAttributes<HTMLDivElement>>"
|
|
16
|
+
- name: ButtonGroupItem
|
|
17
|
+
kind: component
|
|
18
|
+
typeText: "ForwardRefExoticComponent<ButtonGroupItemProps & RefAttributes<HTMLButtonElement>>"
|
|
19
|
+
- name: ButtonGroupItemProps
|
|
20
|
+
kind: type
|
|
21
|
+
- name: ButtonGroupProps
|
|
22
|
+
kind: type
|
|
23
|
+
- name: ButtonGroupSelected
|
|
24
|
+
kind: type
|
|
25
|
+
- name: ButtonGroupSize
|
|
26
|
+
kind: type
|
|
27
|
+
- name: ButtonGroupVariant
|
|
28
|
+
kind: type
|
|
29
|
+
primaryExport: ButtonGroup
|
|
30
|
+
subcomponents:
|
|
31
|
+
- ButtonGroupItem
|
|
32
|
+
props:
|
|
33
|
+
ButtonGroup:
|
|
34
|
+
- name: selected
|
|
35
|
+
type: ButtonGroupSelected
|
|
36
|
+
required: false
|
|
37
|
+
declaredIn: self
|
|
38
|
+
doc: "How an `active` item stands out (only relevant when variant=\"outline\"). `primary` - strong, brand-coloured active cell (view toggle). `muted` - quiet, neutral-grey active cell (filter group)."
|
|
39
|
+
- name: size
|
|
40
|
+
type: ButtonGroupSize
|
|
41
|
+
required: false
|
|
42
|
+
declaredIn: self
|
|
43
|
+
doc: "Item height + type metrics - mirrors Button at the same size."
|
|
44
|
+
- name: variant
|
|
45
|
+
type: ButtonGroupVariant
|
|
46
|
+
required: false
|
|
47
|
+
declaredIn: self
|
|
48
|
+
doc: "Visual mode. `outline` = bordered container with transparent items; `primary` = solid primary surface across all items (split-button look)."
|
|
49
|
+
variantKey: true
|
|
50
|
+
ButtonGroupItem:
|
|
51
|
+
- name: active
|
|
52
|
+
type: boolean
|
|
53
|
+
required: false
|
|
54
|
+
declaredIn: self
|
|
55
|
+
doc: "Marks this item as the currently-selected cell (sets aria-pressed)."
|
|
56
|
+
- name: compact
|
|
57
|
+
type: boolean
|
|
58
|
+
required: false
|
|
59
|
+
declaredIn: self
|
|
60
|
+
doc: "Reduces horizontal padding - use for chevron/icon-only trailing buttons (the dropdown side of a split button)."
|
|
61
|
+
extendsProps:
|
|
62
|
+
- "React.HTMLAttributes<HTMLDivElement>"
|
|
63
|
+
variants:
|
|
64
|
+
variant:
|
|
65
|
+
kind: enum
|
|
66
|
+
options:
|
|
67
|
+
- outline
|
|
68
|
+
- primary
|
|
69
|
+
default: outline
|
|
70
|
+
on: ButtonGroup
|
|
71
|
+
variantSource: cva
|
|
72
|
+
compoundVariants: []
|
|
73
|
+
sizeMaps:
|
|
74
|
+
- PADDING
|
|
75
|
+
dataSlots: []
|
|
76
|
+
dependsOn:
|
|
77
|
+
internal: []
|
|
78
|
+
lib:
|
|
79
|
+
- cn
|
|
80
|
+
hooks: []
|
|
81
|
+
external:
|
|
82
|
+
- class-variance-authority
|
|
83
|
+
- react
|
|
84
|
+
contexts:
|
|
85
|
+
- name: ButtonGroupContext
|
|
86
|
+
type: ButtonGroupContextValue
|
|
87
|
+
default: null
|
|
88
|
+
stories:
|
|
89
|
+
- exportName: Default
|
|
90
|
+
id: components-buttongroup--default
|
|
91
|
+
- exportName: Primary
|
|
92
|
+
id: components-buttongroup--primary
|
|
93
|
+
storybookTitle: Components/ButtonGroup
|
|
94
|
+
docsId: components-buttongroup--documentation
|
|
95
|
+
argTypeOptions: {}
|
|
96
|
+
resolvedCleanly: true
|
|
97
|
+
contractHash: d6be2b861c20
|
|
98
|
+
factsHash: caf30b2341f3
|
|
99
|
+
# >>> AUTHORED - humans own everything below this line. <<<
|
|
100
|
+
status: stable
|
|
101
|
+
summary: "A row of connected buttons sharing one container - view toggles, filter groups, toolbars, split-action buttons."
|
|
102
|
+
useWhen:
|
|
103
|
+
- "several related actions or view options should read as one connected control, not separate buttons"
|
|
104
|
+
- "building a split-action button - a primary action plus a compact chevron or menu trigger"
|
|
105
|
+
useInstead:
|
|
106
|
+
- id: tabs
|
|
107
|
+
when: "the row switches between content panels, not just visual buttons"
|
|
108
|
+
- id: segmented-control
|
|
109
|
+
when: "it is a single-selection view-mode switch that needs a sliding indicator"
|
|
110
|
+
- id: button
|
|
111
|
+
when: "the actions are unrelated and do not need to read as one connected group"
|
|
112
|
+
related:
|
|
113
|
+
- button
|
|
114
|
+
- segmented-control
|
|
115
|
+
tokens:
|
|
116
|
+
- "--primary-weaker"
|
|
117
|
+
- "--primary-weak"
|
|
118
|
+
- "--primary-strong"
|
|
119
|
+
- "--primary-foreground"
|
|
120
|
+
- "--border"
|
|
121
|
+
- "--muted"
|
|
122
|
+
- "--selected"
|
|
123
|
+
- "--foreground"
|
|
124
|
+
- "--background"
|
|
125
|
+
- "--ring"
|
|
126
|
+
a11y:
|
|
127
|
+
notes:
|
|
128
|
+
- "The root carries role=\"group\", a visual grouping only - each ButtonGroupItem's own semantics (a real button, aria-pressed) are what a screen reader actually announces."
|
|
129
|
+
- "active sets aria-pressed, which only communicates a toggle-button state - if the group is really a single-select control, consider whether Tabs or SegmentedControl's stronger semantics fit better before reaching for ButtonGroup."
|
|
130
|
+
requiredProps:
|
|
131
|
+
- "None strictly, but every ButtonGroupItem should carry an accessible name (text or aria-label), the same as a bare Button."
|
|
132
|
+
keyboard:
|
|
133
|
+
- "Each ButtonGroupItem is a native button, so Tab moves between items individually - there is no arrow-key roving tabindex like a real radiogroup or tablist would provide."
|
|
134
|
+
radixHandles: false
|
|
135
|
+
pitfalls:
|
|
136
|
+
- "variant, size, and selected only exist on ButtonGroup - they flow to items through ButtonGroupContext, so setting them on a ButtonGroupItem directly does nothing."
|
|
137
|
+
- "selected is ignored entirely when variant=\"primary\" - it only changes anything in outline mode, the same pattern as Button's elevated only affecting specific variants."
|
|
138
|
+
- "There is no roving-tabindex or arrow-key navigation between items, unlike a native radiogroup or Tabs - do not present ButtonGroup as a fully accessible single-select control without adding that keyboard handling yourself if it matters for the use case."
|
|
139
|
+
canonicalSnippet: |
|
|
140
|
+
import { ButtonGroup, ButtonGroupItem } from "@adres/mgda-ui"
|
|
141
|
+
|
|
142
|
+
<ButtonGroup selected="muted">
|
|
143
|
+
<ButtonGroupItem active>List</ButtonGroupItem>
|
|
144
|
+
<ButtonGroupItem>Grid</ButtonGroupItem>
|
|
145
|
+
</ButtonGroup>
|
|
146
|
+
reviewedAt: 2026-08-31
|
|
147
|
+
reviewedAgainstContractHash: d6be2b861c20
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Usage
|
|
151
|
+
|
|
152
|
+
`ButtonGroup` connects a row of buttons into one visual container - view
|
|
153
|
+
toggles, filter chips, toolbars, and split-action buttons (a primary action
|
|
154
|
+
plus a compact chevron or menu trigger). It is not a replacement for `Tabs`
|
|
155
|
+
(which switches between content panels) or `SegmentedControl` (a single-select
|
|
156
|
+
switch with a sliding indicator) - reach for those when the row's job is
|
|
157
|
+
navigation or exclusive selection rather than a set of related actions.
|
|
158
|
+
|
|
159
|
+
`variant="outline"` (default) draws a bordered container with transparent
|
|
160
|
+
items and dividers between them. `variant="primary"` fills every item with the
|
|
161
|
+
primary surface for a solid split-button look; in that mode `selected` has no
|
|
162
|
+
effect, since every cell already reads as active.
|
|
163
|
+
|
|
164
|
+
In outline mode, `selected` controls how an `active` item stands out:
|
|
165
|
+
`primary` (default) for a strong, brand-coloured active cell, the right choice
|
|
166
|
+
for a view toggle, and `muted` for a quiet, neutral active cell, better suited
|
|
167
|
+
to a filter group where the active filter should not look like the primary
|
|
168
|
+
action.
|
|
169
|
+
|
|
170
|
+
## Anatomy
|
|
171
|
+
|
|
172
|
+
| Part | Role |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| `ButtonGroup` | The container. Owns `size`, `variant`, and `selected`, and shares them with every item through context. Sets `role="group"`. |
|
|
175
|
+
| `ButtonGroupItem` | A native `button`. Reads its visual state from context plus its own `active`/`compact` props - `active` sets `aria-pressed` and picks the selected styling; `compact` tightens padding for an icon/chevron-only cell. |
|
|
176
|
+
|
|
177
|
+
`ButtonGroupContext` is why `size`/`variant`/`selected` only need to be set
|
|
178
|
+
once, on the root - passing them to an individual `ButtonGroupItem` has no
|
|
179
|
+
effect.
|