Draft: Merge status into feedback design tokens
Background
Feedback and status design token categories have historically had less than ideal separation in definition and use than other design token categories. So much so that we have dedicated documentation on deciding between the two.
Proposal
- Combine status and feedback design tokens into a single feedback category.
- Add border design tokens to support more use cases.
- Update feedback definition to encompass a range of meaning from things that happen as a result of something else to things that are in a particular state of meaning.
Visual updates TBD…
Considerations
Constants used in status and feeback
Status Token Color Constants
| Status Type | Element | Light Mode | Dark Mode |
|---|---|---|---|
| Neutral | Background | {color.neutral.100} |
{color.neutral.800} |
| Text | {color.neutral.700} |
{color.neutral.200} |
|
| Icon | {color.neutral.500} |
{color.neutral.300} |
|
| Info | Background | {color.blue.100} |
{color.blue.800} |
| Text | {color.blue.700} |
{color.blue.200} |
|
| Icon | {color.blue.500} |
{color.blue.300} |
|
| Success | Background | {color.green.100} |
{color.green.800} |
| Text | {color.green.700} |
{color.green.200} |
|
| Icon | {color.green.500} |
{color.green.300} |
|
| Warning | Background | {color.orange.100} |
{color.orange.800} |
| Text | {color.orange.700} |
{color.orange.200} |
|
| Icon | {color.orange.500} |
{color.orange.300} |
|
| Danger | Background | {color.red.100} |
{color.red.800} |
| Text | {color.red.700} |
{color.red.200} |
|
| Icon | {color.red.500} |
{color.red.300} |
|
| Brand | Background | {color.purple.100} |
{color.purple.900} |
| Text | {color.purple.700} |
{color.purple.300} |
|
| Icon | {color.purple.500} |
{color.purple.500} |
Feedback Token Color Constants
| Feedback Type | Element | Light Mode | Dark Mode |
|---|---|---|---|
| Neutral | Background | {color.neutral.50} |
{color.neutral.900} |
| Text | {color.neutral.700} |
{color.neutral.200} |
|
| Icon | {color.neutral.600} |
{color.neutral.300} |
|
| Info | Background | {color.blue.50} |
{color.blue.950} |
| Text | {color.blue.700} |
{color.blue.200} |
|
| Icon | {color.blue.600} |
{color.blue.300} |
|
| Success | Background | {color.green.50} |
{color.green.900} |
| Text | {color.green.700} |
{color.green.200} |
|
| Icon | {color.green.600} |
{color.green.300} |
|
| Warning | Background | {color.orange.50} |
{color.orange.900} |
| Text | {color.orange.700} |
{color.orange.200} |
|
| Icon | {color.orange.600} |
{color.orange.300} |
|
| Danger | Background | {color.red.50} |
{color.red.900} |
| Text | {color.red.700} |
{color.red.200} |
|
| Icon | {color.red.600} |
{color.red.300} |
|
| Strong | Background | {color.neutral.800} |
(no dark variant) |
| Text | {color.neutral.0} |
(no dark variant) | |
| Icon | {color.neutral.0} |
(no dark variant) | |
| Link | {color.blue.300} |
(no dark variant) |
Key overlaps
Complete overlaps (same color constant used)
Text colors for all types are identical in both systems:
- Neutral, Info, Success, Warning, Danger all use
{color.[type].700}in light mode - All use
{color.[type].200}in dark mode
Icon colors in dark mode are identical:
- All use
{color.[type].300}for their respective types
Partial overlaps
-
Neutral icon in dark mode: Both use
{color.neutral.300} -
Blue/Info icon in dark mode: Both use
{color.blue.300} -
Green/Success icon in dark mode: Both use
{color.green.300} -
Orange/Warning icon in dark mode: Both use
{color.orange.300} -
Red/Danger icon in dark mode: Both use
{color.red.300}
Key differences
- Background colors
-
Status: Uses stronger backgrounds -
100(light) /800(dark) -
Feedback: Uses lighter backgrounds -
50(light) /900-950(dark) - Result: Status is more prominent/saturated for indicating ongoing states
-
Status: Uses stronger backgrounds -
- Icon colors in light mode
-
Status: Uses
500level colors (more saturated) -
Feedback: Uses
600level colors (slightly darker)
-
Status: Uses
- Neutral backgrounds
-
Status:
neutral.100/neutral.800 -
Feedback:
neutral.50/neutral.900 - Result: Feedback is lighter than status in light mode, and darker than status in dark mode
-
Status:
- Special variants
- Status: Has a Brand variant using purple colors (no use of the brand variant turned up in the results below)
- Feedback: Has a Strong variant with inverted high-contrast colors
- Note: Strong feedback doesn't have dark mode variants
Additional design tokens
Feedback-specific
-
feedback.border.radius:{border.radius.lg}- Border radius for feedback elements
Current status usage
Usage in the monolith identified by git grep -E "gl-[a-zA-Z-]*status[a-zA-Z-]*(success|warning|danger|info|neutral)" | cat (not including specs or other use of "status," like illustrations).
Monolith
Known uses…
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: backgroundClass: 'gl-bg-status-success',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: foregroundClass: 'gl-fill-status-success',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: backgroundClass: 'gl-bg-status-danger',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: foregroundClass: 'gl-fill-status-danger',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: backgroundClass: 'gl-bg-status-info',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: foregroundClass: 'gl-fill-status-info',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: backgroundClass: 'gl-bg-status-neutral',
app/assets/javascripts/merge_request_dashboard/components/user_avatar.vue: foregroundClass: 'gl-fill-status-neutral',
app/assets/javascripts/notes/components/multiline_comment_utils.js: 'gl-bg-status-success gl-text-status-success': symbol === '+',
app/assets/javascripts/notes/components/multiline_comment_utils.js: 'gl-bg-status-danger gl-text-status-danger': symbol === '-',
app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue: :class="{ '!gl-text-status-info': subscribed }"
app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue: :class="{ '!gl-text-status-info': subscribed }"
app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue: :class="{ '!gl-text-status-info': hasTodo }"
app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue: :class="{ '!gl-text-status-info': hasTodo }"
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-danger',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-danger',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-warning',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-warning',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-success',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-success',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-neutral',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-neutral',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-danger',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-danger',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-neutral',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-neutral',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-info',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-info',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-info',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-info',
app/assets/javascripts/vue_merge_request_widget/constants.js: backgroundClass: 'gl-bg-status-neutral',
app/assets/javascripts/vue_merge_request_widget/constants.js: iconClass: 'gl-fill-status-neutral',
app/assets/javascripts/whats_new/components/feature.vue: class="gl-my-1 gl-mr-1 gl-text-status-info"
app/assets/javascripts/wikis/components/wiki_header.vue: :class="{ '!gl-text-status-info': wikiPage.subscribed }"
app/assets/javascripts/wikis/components/wiki_sidebar_entry.vue: (match) => `<span class="gl-bg-status-warning">${match}</span>`,
app/assets/javascripts/work_items/components/shared/todos_toggle.vue: :class="{ '!gl-text-status-info': pendingTodo }"
app/assets/javascripts/work_items/components/work_item_notifications_widget.vue: :class="{ '!gl-text-status-info': workItemNotificationsSubscribed }"
app/assets/stylesheets/framework/animations.scss: background-color: var(--gl-status-info-icon-color);
app/assets/stylesheets/framework/animations.scss: background-color: rgb(from var(--gl-status-info-icon-color) r g b / 0.7);
app/assets/stylesheets/framework/diffs.scss: border: 1px solid var(--gl-status-danger-icon-color);
app/assets/stylesheets/framework/diffs.scss: border: 1px solid var(--gl-status-success-icon-color);
app/assets/stylesheets/framework/diffs.scss: border: 1px solid var(--gl-status-danger-icon-color);
app/assets/stylesheets/framework/diffs.scss: border: 1px solid var(--gl-status-success-icon-color);
app/assets/stylesheets/framework/sidebar.scss: color: var(--gl-status-warning-icon-color);
app/assets/stylesheets/page_bundles/design_management.scss: background-color: var(--gl-status-warning-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: background-color: var(--gl-status-neutral-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-color: var(--gl-status-success-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-background-color: var(--gl-status-success-background-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-color: var(--gl-status-danger-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-background-color: var(--gl-status-danger-background-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-color: var(--gl-status-info-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-background-color: var(--gl-status-info-background-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-color: var(--gl-status-warning-icon-color);
app/assets/stylesheets/page_bundles/notes/_system_notes.scss: --system-note-icon-background-color: var(--gl-status-warning-background-color);
app/assets/stylesheets/page_bundles/profile.scss: fill: var(--gl-status-neutral-icon-color) !important;
app/assets/stylesheets/page_bundles/work_item_settings.scss: background-color: var(--gl-status-info-icon-color);
app/assets/stylesheets/page_bundles/work_item_settings.scss: background-color: var(--gl-status-info-icon-color);
app/assets/stylesheets/page_bundles/work_item_settings.scss: box-shadow: 0 0 0 2px var(--gl-status-info-icon-color);
app/assets/stylesheets/page_bundles/work_item_settings.scss: background-color: var(--gl-status-info-icon-color);
app/assets/stylesheets/page_bundles/work_item_settings.scss: border: 1px solid var(--gl-status-neutral-icon-color);
app/assets/stylesheets/pages/events.scss: @apply gl-fill-status-success;
app/assets/stylesheets/pages/events.scss: @apply gl-fill-status-danger;
app/assets/stylesheets/pages/events.scss: @apply gl-fill-status-info;
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-green-100 dark:gl-border-green-700 gl-bg-status-success';
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-red-100 dark:gl-border-red-700 gl-bg-status-danger';
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-blue-100 dark:gl-border-blue-700 gl-bg-status-info';
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-orange-100 dark:gl-border-orange-700 gl-bg-status-warning';
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-neutral-100 dark:gl-border-neutral-100 gl-bg-status-neutral';
ee/app/assets/javascripts/ai/duo_agents_platform/components/common/agent_status_icon.vue: return 'gl-border-neutral-100 dark:gl-border-neutral-700 gl-bg-status-neutral';
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/details_drawer.vue: <span v-if="status.failCount" class="gl-text-status-danger">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/details_drawer.vue: <span v-if="status.pendingCount" class="gl-text-status-neutral">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/details_drawer.vue: <span v-if="status.passCount" class="gl-text-status-success">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/statuses_list.vue: <span v-if="controlStatus.status === 'FAIL'" class="gl-text-status-danger">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/statuses_list.vue: <span v-if="getControlStatusFixes(controlStatus).length" class="gl-text-status-neutral">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/statuses_list.vue: <span v-if="controlStatus.status === 'PENDING'" class="gl-text-status-neutral">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/details_drawer/statuses_list.vue: <span v-if="controlStatus.status === PASS_STATUS" class="gl-text-status-success">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/grouped_table/grouped_table.vue: <span class="gl-text-status-danger">
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: text: 'gl-text-status-danger',
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: fill: 'gl-fill-status-danger',
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: text: 'gl-text-status-neutral',
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: fill: 'gl-fill-status-neutral',
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: text: 'gl-text-status-success',
ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/components/requirement_status.vue: fill: 'gl-fill-status-success',
ee/app/assets/javascripts/security_configuration/components/security_attributes/category_list.vue: class="gl-my-1 gl-flex gl-cursor-pointer gl-items-center gl-rounded-base gl-p-3 hover:!gl-bg-status-neutral"
ee/app/assets/javascripts/security_inventory/components/group_tool_coverage_indicator.vue: class="gl-text-sm gl-text-status-neutral"
ee/app/assets/javascripts/security_inventory/components/sidebar/expandable_group.vue: class="gl-relative gl-m-1 gl-flex gl-h-8 gl-cursor-pointer gl-items-center gl-gap-4 gl-rounded-base gl-px-3 hover:!gl-bg-status-neutral"
ee/app/assets/javascripts/security_inventory/components/sidebar/subgroup_sidebar.vue: class="gl-relative gl-ml-1 gl-mt-6 gl-flex gl-h-8 gl-cursor-pointer gl-items-center gl-gap-4 gl-rounded-base gl-px-3 hover:!gl-bg-status-neutral"
ee/app/assets/javascripts/security_inventory/components/vulnerability_indicator.vue: <span class="gl-text-sm gl-text-status-neutral">
ee/app/views/projects/issues/_health_status.html.haml:- status_classes = { 'at_risk' => 'gl-bg-status-danger gl-text-status-danger', 'on_track' => 'gl-bg-status-success gl-text-status-success', 'needs_attention' => 'gl-bg-status-warning gl-text-status-warning' }
Usage breakdown…
- 94 total instances
- 24 unique classes/variables
- Most used: `--gl-status-info-icon-color (10)
Pajamas
Known uses…
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/design-tokens-using.md:
contents/product-foundations/layout.md:
packages/gitlab-ui/src/components/base/avatars_inline/avatars_inline.scss: background-color: var(--gl-status-neutral-background-color);
packages/gitlab-ui/src/components/base/avatars_inline/avatars_inline.scss: color: var(--gl-status-neutral-text-color);
packages/gitlab-ui/src/components/base/markdown/markdown.scss: @apply gl-bg-status-danger;
packages/gitlab-ui/src/components/base/markdown/markdown.scss: @apply gl-bg-status-success;
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue:
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue:
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue: class="dashboard-card-skeleton-info gl-mb-3 gl-w-full gl-bg-status-neutral gl-py-3"
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue:
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue:
packages/gitlab-ui/src/components/regions/dashboard_skeleton/dashboard_skeleton.vue:
packages/gitlab-ui/src/directives/resize_observer/resize_observer.stories.js: class="gl-flex gl-relative gl-justify-center gl-items-center gl-bg-status-neutral gl-text-default">
Edited by Jeremy Elder
