---
id: brandmark
category: Brand
title: Brandmark
description: Logos/Brandmarks for Optum brands.
design: 'https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/Abyss-Web?type=design&node-id=0-21&mode=design&t=uWtmzWwvT2Kv5MMG-0'
---
```jsx
import { Brandmark } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Brandmark',
inputs: [
{
prop: 'size',
type: 'string',
default: '$brandmark.sizing.lg'
},
{
prop: 'affiliate',
type: 'select',
options: [
{ label: 'optum', value: 'optum' },
{ label: 'optum_financial', value: 'optum_financial' },
{ label: 'optum_frontier_therapies', value: 'optum_frontier_therapies' },
{ label: 'optum_health-education', value: 'optum_health-education' },
{ label: 'optum_now', value: 'optum_now' },
{ label: 'optum_perks', value: 'optum_perks' },
{ label: 'optum_prescription', value: 'optum_prescription' },
{ label: 'optum_serve', value: 'optum_serve' },
{ label: 'optum_store', value: 'optum_store' },
],
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'lockup', value: 'lockup' },
]
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'white', value: 'white' },
{ label: 'black', value: 'black' },
{ label: 'orange', value: 'orange' },
]
},
]
}
// Disclaimer: not all affiliate variant/color combinations are applicable, and inapplicable combinations will display as empty
```
## Brand
Use the `brand` property to adjust which brand is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of the brandmark.
```jsx live
```
## Affiliate
Use the `affiliate` property to select the required brandmark affiliates.
```jsx live
```
## Variant
Use the `variant` property to select the required brandmark variants.
```jsx live
```
## Color
Use the `color` property to select available brandmark colors.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Brandmarks
```
The source for these brandmarks can be found in the Brandmark Library.
You can use the search functionality to find the required brandmark. Brandmarks can be searched using their affiliates, variants or colors.
```jsx render
```
---
id: icon-brand
category: Brand
title: IconBrand
description: Used to implement Brand icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=5%3A159&t=yumeSCoKoGQjs5PJ-0
---
```jsx
import { IconBrand } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconBrand',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'one tone', value: 'onetone' },
{ label: 'two tone', value: 'twotone' },
{ label: 'one tone w/ dark circle', value: 'onetonedarkcircle' },
{ label: 'two tone w/ dark circle', value: 'twotonedarkcircle' },
{ label: 'two tone w/ light circle', value: 'twotonelightcircle' },
],
},
{
prop: 'icon',
type: 'string',
},
]
}
```
## Icons
Use the `icon` property to adjust which icon is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number, or using a token. The default is `$md`.
Token sizes: `$xs`: 40 `$sm`: 64 `$md`: 96 `$lg`: 112 `$xl`: 136
```jsx live
```
## Brand Icon Variants
Use the `variant` property to change the style of Brand icons. Available variants are `twotonedarkcircle`, `twotonelightcircle`, `twotone`, `onetonedarkcircle`, and `onetone`. The default variant is `twotonedarkcircle`.
**Note:** The `variant` prop is ignored if `useDeprecated` is set to false or if the `deprecatedOptumIcons` override is set in `createTheme`, as the new icons only have one variant.
```jsx live
onetonedarkcircletwotonedarkcircletwotonelightcircleonetonetwotone
```
```jsx render
```
```jsx render
```
```jsx render
Brand Icons
```
Abyss uses branded iconography iconography that is designed to aid wayfinding, draw
attention, and support messaging.
The source for these design icons can be found in the Brand Icons Library.
```jsx render
```
---
id: icon-custom
category: Brand
title: IconCustom
description: Used to implement custom icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=5%3A159&t=yumeSCoKoGQjs5PJ-0
---
```jsx
import { IconCustom } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconCustom',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'light', value: 'light' },
{ label: 'lightactive', value: 'lightactive' },
],
},
{
prop: 'icon',
type: 'string',
},
]
}
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number or token. The default size is set to 24.
Token sizes: `$xs`: 16 `$sm`: 20 `$md`: 24 `$lg`: 40 `$xl`: 48
```jsx live
```
## Variants
Use the `variant` prop to change the style of the custom icons. The prop takes in either a `light` or `lightactive` value. The default is `light`.
```jsx live
lightlightactive
```
## Brand
Use the `brand` property to adjust which brands icons are being selected. Note that some of the icons unique to certain brands.
The default is the theme brand, then falls back to `uhc`.
```jsx live
```
## Active
When placing an icon inside of a clickable element, the icon should be toggled between its normal and active state.
```jsx live
{({ pressed }) => (
Home
)}
```
## Indicator
The [indicator component](/mobile/ui/indicator) can be used as a wrapper to add a notification badge.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Custom Icons
```
```jsx render
```
---
id: illustration-brand
category: Media
title: IllustrationBrand
description: Used to implement Brand illustrations and adapt their properties.
design: 'https://www.figma.com/file/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-Abyss-Mobile?type=design&node-id=1218-19509&mode=design&t=eobYuZOIhhms55Vc-0'
---
```jsx
import { IllustrationBrand } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IllustrationBrand',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'illustration',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 1, value: 1 },
{ label: 2, value: 2 },
],
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'primary', value: 'primary' },
{ label: 'pacific', value: 'pacific' },
{ label: 'white', value: 'white' },
]
},
]
}
// Disclaimer: not all brand color combinations or variants are applicable, and inapplicable combinations will display as empty
```
## Brand
Use the `brand` property to adjust which brand is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of the illustration.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Illustration Source
```
The source for these illustrations can be found in the brand libraries.
UnitedHealthCare Library
Optum Library
You can use the search functionality to find the required illustration.
Illustrations can be searched using their title, variants or colors.
---
id: elevation
category: Brand
title: Elevation
description: Creates depth on screen for users
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=12804%3A65751
---
```jsx
import { Elevation } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Elevation',
inputs: [
{
prop: 'level',
type: 'select',
options: [
{ label: "0", value: 0 },
{ label: "1", value: 1 },
{ label: "2", value: 2 },
{ label: "3", value: 3 },
{ label: "4", value: 4 },
]
},
]
}
```
## Level
The `level` prop determines the magnitude of the shadow effect applied to the surface of the component.
The prop accepts numbers between `0` and `4`. The default is `1`
```jsx live
Level 0
Level 1
Level 2
Level 3
Level 4
```
```jsx render
```
```jsx render
```
---
id: tokens
title: Tokens
category: Brand
---
## Overview
Design tokens are the visual sub-atom variables of a design system. They contain UI data such as colors, border width, elevation, and even motion.
They are used in the place of hard-coded values such as hex codes or pixels to maintain scalability and consistency.
Think about them as recipe ingredients - you could add chocolate to a salad, but it won't be very tasty.
You would only consider what is a standard salad ingredient - it's the same with tokens, they are a limited set of options that make sense for our product.
**Further reading:**
[Nathan Curtis on Tokens in design systems](https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421).
### Token Hierarchy
Abyss uses a 3-tier token system:
- Core tier - the WHAT or the OPTIONS: contains primitive values, with no specific meaning - the name of the token and its raw value (HEX code for colors, and numbers for borders, corner radius, opacity, etc.)
- Semantic tier - the HOW or the DECISIONS: communicates design decisions on the exact usage of a Core token system-wide.
- Brand tokens - shorthand tokens to define common colors used throughout Abyss.
### Using Tokens
Before you can consume Abyss tokens, your project must be configured with our [themeProvider](/mobile/ui/theme-provider). This will allow you to access the tokens in your project.
Tokens are used in place of hard-coded values such as hex codes or pixels. To use a token, you can reference it in your code using the `$` symbol followed by the token name.
All Abyss components can accept tokens, when they are passed in using the `style`, or [styles](/mobile/developers/style-customization) prop. Non-Abyss components can use the [tokenize](/mobile/tools/tokenize) function to accept tokens.
#### Examples
Brand tokens are useful for quickly defining the color of components.
```jsx sandbox
```
#### Styled Function
To create a `View` component with a background color of `$core.color.brand.100`, you can leverage our [styled function](/mobile/tools/styled) and do the following:
```jsx sandbox
() => {
const Example = styled('View', {
backgroundColor: '$core.color.brand.100',
height: 100,
width: 100,
});
return ;
};
```
#### useToken hook
Alternatively, you can use our [useToken Hook](/mobile/hooks/use-token) to directly access the value of a token. This is useful when you need the value of multiple tokens.
```jsx sandbox
() => {
const getColorToken = useToken('colors');
const green = getColorToken('$core.color.green.100');
const red = getColorToken('$core.color.red.100');
return (
<>
>
);
};
```
#### Tokenize Function
Our [tokenize](/mobile/tools/tokenize) function is useful for mapping any non-Abyss component's props to accept Abyss tokens.
```jsx live
const TokenizedTouchableHighlight = tokenize(TouchableHighlight, {
underlayColor: 'colors',
});
render(() => {
return (
{}}
accessibilityRole="button"
>
Press Me
);
});
```
#### Useful Links
- [Custom Theme Tutorial](/mobile/developers/tutorials/custom-themes/): This tutorial will guide you through creating a custom Abyss theme for your project.
- [createTheme Function](/mobile/tools/create-theme): This tool allows you to create and modify themes to fit your design needs.
- [Theme Provider](/mobile/ui/theme-provider): Provider that passes the theme object down the component tree giving your project access to Abyss tokens.
- [styled Function](/mobile/tools/styled): Tool that allows you to create styled components.
- [useToken Hook](/mobile/hooks/use-token): Hook that allows you to access the value of a token in your project.
- [tokenize](/mobile/tools/tokenize): Function that allows you to map a component's props to accept Abyss tokens.
## Core Tokens
Below is a list of core tokens used throughout Abyss, These are split into the categories `color`, `border-width`, `border-radius`, `opacity`, `spacing`, `sizing`.
_**Note:** Click on the token row to copy the token to your clipboard._
#### Border Width Tokens
`border-width` tokens are used to define the `borderWidth` on components.
```jsx
const Example = styled('View', {
borderWidth: '$core.border-width.md',
});
```
```jsx render
```
#### Border Radius Tokens
`border-radius` tokens are used to define the `borderRadius` on components.
```jsx
const Example = styled('View', {
borderRadius: '$core.border-radius.md',
});
```
```jsx render
```
---
#### Opacity Tokens
`opacity` tokens are used to define the opacity of a component.
```jsx
const Example = styled('View', {
opacity: '$core.opacity.md',
});
```
```jsx render
```
---
#### Spacing Tokens
`spacing` tokens define the space between components. Generally, these are used for the `padding`, `margin`, or `gap` of components.
```jsx
const Example = styled('View', {
padding: '$core.spacing.200',
});
```
```jsx render
```
---
#### Sizing Tokens
`sizing` tokens define the size of components. Generally, these will be used to define the `width` or `height`.
```jsx
const Example = styled('View', {
width: '$core.sizing.600',
height: '$core.sizing.600',
});
```
```jsx render
```
---
#### Color Tokens
`color` tokens are used to define the color of components.
```jsx
const Example = styled('View', {
backgroundColor: '$core.color.brand.100',
});
```
```jsx render
```
## Brand Tokens
Brand tokens are useful for quickly defining the color of components.
_**Note:** Click on the token row to copy the token to your clipboard._
#### Colors
Below is a list of brand tokens and their intended use cases.
```jsx
const Example = styled('View', {
backgroundColor: '$primary1',
});
```
```jsx render
```
---
#### Spacing
`spacing` tokens define the space between components. Generally, these will be used to define the `padding`, `margin`, or `gap` of components.
```jsx
const Example = styled('View', {
padding: '$md',
});
```
```jsx render
```
---
#### Border Radius
`border-radius` tokens define the `borderRadius` on components.
```jsx
const Example = styled('View', {
borderRadius: '$md',
});
```
```jsx render
```
---
### Accessibility
Color choices that are accessible ensure everyone can not only see every element on a page but also understand a specific, intended meaning. You want everyone to be able to see the difference between two colors right next to or on top of each other.
Contrast refers to the perceived difference between foreground and background colors. People with low vision or color blindness and those with difficulty seeing the differences between colors can have trouble seeing where one element ends and another begins. As we age, the shape of our eyes changes and affects how we perceive color and how well we can distinguish color variations. If the contrast between different elements is too low, people may not be able to see them at all.
Contrast is expressed as a ratio with the first number representing the foreground color and the second representing the background color. For example, 3:1 means the foreground item color is three times more intense or visible than the background value. Contrast rules apply to text as well as any content that conveys meaning, including icons, graphics, and form elements. Tools such as Colour Contrast Analyzer or WebAIM's online color contrast tool are useful for verifying contrast ratios.
Color and contrast choices within a digital experience are accessible when people can:
- See UI elements and content
- Understand and interpret information
- Take action
We aim to provide a contrast ratio perceivable by all users. For this reason, UnitedHealthcare has embraced a minimum contrast ratio of 4.5:1 (foreground vs background) for UI elements and content that conveys meaning.
Recommendations
- Include color combinations, good contrast and poor contrast, in design documentation
- Communicate meaning with more than just color, such as with color and descriptive text
- Give focus indicators a unique presentation that meets contrast requirements on all backgrounds
Test for a minimum contrast ratio of 4.5 to 1 for:
- Non-bolded text smaller than 24 pixels (18 points)
- Bold text smaller than 18 pixels (14 points)
- Essential icons that are close to the body text size
Test that non-text elements that communicate information meet a minimum
contrast ratio of 3 to 1 for all states:
- Icons
- Data visualizations
- Focus indicators
- Controls, including their borders or boundaries
- Non-bolded text at or above 24 pixels (18 points)
- Bold text at or above 18 pixels (14 points)
Don't worry about contrast for logos and disabled elements. Watch out for using color alone to communicate meaning. People who are color blind or blind cannot perceive the meaning by color alone.
---
id: brandmark
category: Brand
title: Brandmark
description: Logos/Brandmarks for UHC brands.
design: 'https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/Abyss-Web?type=design&node-id=0-21&mode=design&t=uWtmzWwvT2Kv5MMG-0'
---
```jsx
import { Brandmark } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Brandmark',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'affiliate',
type: 'select',
options: [
{ label: 'aarp_extra_assurance_benefits', value: 'aarp_extra_assurance_benefits' },
{ label: 'aarp_medicare_advantage_walgreens', value: 'aarp_medicare_advantage_walgreens' },
{ label: 'aarp_medicare_advantage', value: 'aarp_medicare_advantage' },
{ label: 'aarp_medicare_plans', value: 'aarp_medicare_plans' },
{ label: 'aarp_medicare_prescription', value: 'aarp_medicare_prescription' },
{ label: 'aarp_medicare_prescription_walgreens', value: 'aarp_medicare_prescription_walgreens' },
{ label: 'aarp_medicare_supplement', value: 'aarp_medicare_supplement' },
{ label: 'aarp_supplemental_personal_health', value: 'aarp_supplemental_personal_health' },
{ label: 'community_plan', value: 'community_plan' },
{ label: 'dental', value: 'dental' },
{ label: 'dual_complete', value: 'dual_complete' },
{ label: 'global', value: 'global' },
{ label: 'hearing', value: 'hearing' },
{ label: 'medicare_advantage', value: 'medicare_advantage' },
{ label: 'group_medicare_advantage', value: 'group_medicare_advantage' },
{ label: 'medicare_plans', value: 'medicare_plans' },
{ label: 'medicare_solutions', value: 'medicare_solutions' },
{ label: 'oxford', value: 'oxford' },
{ label: 'student_resources', value: 'student_resources' },
{ label: 'uhc', value: 'uhc' },
{ label: 'vision', value: 'vision' },
],
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'lockup', value: 'lockup' },
{ label: 'lockup_horizontal', value: 'lockup_horizontal' },
{ label: 'u_mark', value: 'u_mark' },
{ label: 'u_mark_horizontal', value: 'u_mark_horizontal' },
{ label: 'monogram', value: 'monogram' },
{ label: 'stacked_wordmark', value: 'stacked_wordmark' },
{ label: 'wordmark', value: 'wordmark' },
]
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'red', value: 'red' },
{ label: 'white', value: 'white' },
{ label: 'black', value: 'black' },
{ label: 'blue', value: 'blue' },
{ label: 'full', value: 'full' },
]
},
]
}
// Disclaimer: not all affiliate variant/color combinations are applicable, and inapplicable combinations will display as empty
```
## Brand
Use the `brand` property to adjust which brand is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of the brandmark.
```jsx live
```
## Affiliate
Use the `affiliate` property to select the required brandmark affiliates.
```jsx live
```
## Variant
Use the `variant` property to select the required brandmark variants.
```jsx live
```
## Color
Use the `color` property to select available brandmark colors.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
Brandmarks
```
The source for these brandmarks can be found in the Brandmark Library.
You can use the search functionality to find the required brandmark. Brandmarks can be searched using their affiliates, variants or colors.
```jsx render
```
---
id: icon-brand
category: Brand
title: IconBrand
description: Used to implement Brand icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=5%3A159&t=yumeSCoKoGQjs5PJ-0
---
```jsx
import { IconBrand } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconBrand',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'one tone', value: 'onetone' },
{ label: 'two tone', value: 'twotone' },
{ label: 'one tone w/ dark circle', value: 'onetonedarkcircle' },
{ label: 'two tone w/ dark circle', value: 'twotonedarkcircle' },
{ label: 'two tone w/ light circle', value: 'twotonelightcircle' },
],
},
{
prop: 'icon',
type: 'string',
},
]
}
```
## Icons
Use the `icon` property to adjust which icon is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number, or using a token. The default is `$md`.
Token sizes: `$xs`: 40 `$sm`: 64 `$md`: 96 `$lg`: 112 `$xl`: 136
```jsx live
```
## Brand Icon Variants
Use the `variant` property to change the style of Brand icons. Available variants are `twotonedarkcircle`, `twotonelightcircle`, `twotone`, `onetonedarkcircle`, and `onetone`. The default variant is `twotonedarkcircle`.
```jsx live
onetonedarkcircletwotonedarkcircletwotonelightcircleonetonetwotone
```
```jsx render
```
```jsx render
```
```jsx render
Brand Icons
```
Abyss uses branded iconography that is designed to aid way-finding, draw attention,
and support messaging.
The source for these design icons can be found in the Brand Icons Library.
## Dynamic Type
Brand icons do not scale. When using IconBrand, the `disabledScaling` prop should be set to `true`.
```jsx render
```
---
id: icon-custom
category: Brand
title: IconCustom
description: Used to implement custom icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=5%3A159&t=yumeSCoKoGQjs5PJ-0
---
```jsx
import { IconCustom } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconCustom',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'light', value: 'light' },
{ label: 'lightactive', value: 'lightactive' },
],
},
{
prop: 'icon',
type: 'string',
},
]
}
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number or token. The default size is set to 24.
Token sizes: `$xs`: 16 `$sm`: 20 `$md`: 24 `$lg`: 40 `$xl`: 48
```jsx live
```
## Variants
Use the `variant` prop to change the style of the custom icons. The prop takes in a `light` and `dark` value, as well as
`lightactive` and `darkactive` counterparts. The default is `light`.
```jsx live
lightlightactivedarkdarkactive
```
## Brand
Use the `brand` property to adjust which brands icons are being selected. Note that some of the icons unique to certain brands.
The default is the theme brand, then falls back to `uhc`.
```jsx live
```
## Active
When placing an icon inside of a clickable element, the icon should be toggled between its normal and active state.
```jsx live
{({ pressed }) => (
Home
)}
```
## Indicator
The [indicator component](/mobile/ui/indicator) can be used as a wrapper to add a notification badge.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Custom Icons
```
```jsx render
```
---
id: illustrated-icon-brand
slug: /mobile/brand/uhc/illustrated-icon-brand
category: Brand
title: IllustratedIconBrand
description: Used to implement UHC brand illustrated icons and adapt their properties.
sourceIsTS: true
---
```jsx
import { IllustratedIconBrand } from '@uhg-abyss/mobile';
```
```tsx sandbox
{
component: 'IllustratedIconBrand',
inputs: [
{
prop: 'icon',
type: 'string',
},
{
prop: 'size',
type: 'string',
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'none', value: undefined },
{ label: 'gold', value: 'gold' },
{ label: 'orange', value: 'orange' },
{ label: 'multicolor', value: 'multicolor' },
]
},
],
}
// Disclaimer: Not all icon/color combinations are applicable; inapplicable combinations will display as empty
```
## Size
Use the `size` property to adjust the width of the illustrated icon. The default value is `100`. The height of the illustration will scale proportionally to the width.
```tsx live
```
## Color
Use the `color` property to select available illustrated icon colors. The available colors are `"gold"`, `"orange"`, and `"multicolor"`.
**Note:** Not all illustrated icons have any color variants. In such cases, omit the `color` prop; otherwise, the icon will not display.
```tsx live
```
```jsx render
```
```jsx render
```
Screen Reader Support
Illustrated icons are intended to be used as decorative images and as such, are ignored by screen readers by default. However, should a case arise in which an illustrated icon needs to be accessible, use the `accessibilityLabel` prop to provide accessible text to the image. This text should be descriptive enough to convey the meaning of the illustrated icon.
```tsx live
```
```jsx render
Illustrated Icon Source
```
The source for these illustrated icons can be found in the brand libraries.
UnitedHealthCare Library
You can use the search functionality to find the required illustrated icons. Icons can be searched using their title or colors.
---
id: illustration-brand
category: Brand
title: IllustrationBrand
description: Used to implement Brand illustrations and adapt their properties.
design: 'https://www.figma.com/file/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-Abyss-Mobile?type=design&node-id=1218-19509&mode=design&t=eobYuZOIhhms55Vc-0'
---
```jsx
import { IllustrationBrand } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IllustrationBrand',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'illustration',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: '1', value: '1' },
{ label: '2', value: '2' },
],
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'primary', value: 'primary' },
{ label: 'pacific', value: 'pacific' },
{ label: 'white', value: 'white' },
]
},
]
}
// Disclaimer: not all brand color combinations or variants are applicable, and inapplicable combinations will display as empty
```
## Brand
Use the `brand` property to adjust which brand is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of the illustration.
```jsx live
```
## Color
Use the `color` property to select available illustration colors.
```jsx live
```
## Variant
Some UHC illustrations have multiple variants of accent colors on the same background color. Use the `variant` prop to select the color combination.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Illustration Source
```
The source for these illustrations can be found in the brand libraries.
UnitedHealthCare Library
Optum Library
You can use the search functionality to find the required illustration.
Illustrations can be searched using their title, variants or colors.
---
id: elevation
category: Brand
title: Elevation
description: Creates depth on screen for users
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=12804%3A65751
---
```jsx
import { Elevation } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Elevation',
inputs: [
{
prop: 'level',
type: 'select',
options: [
{ label: "0", value: 0 },
{ label: "1", value: 1 },
{ label: "2", value: 2 },
{ label: "3", value: 3 },
{ label: "4", value: 4 },
]
},
]
}
```
## Level
The `level` prop determines the magnitude of the shadow effect applied to the surface of the component.
The prop accepts numbers between `0` and `4`. The default is `1`
```jsx live
Level 0
Level 1
Level 2
Level 3
Level 4
```
```jsx render
```
```jsx render
```
---
id: tokens
title: Tokens
category: Brand
---
## Overview
Design tokens are the visual sub-atom variables of a design system. They contain UI data such as colors, border width, elevation, and even motion.
They are used in the place of hard-coded values such as hex codes or pixels to maintain scalability and consistency.
Think about them as recipe ingredients - you could add chocolate to a salad, but it won't be very tasty.
You would only consider what is a standard salad ingredient - it's the same with tokens, they are a limited set of options that make sense for our product.
**Further reading:**
[Nathan Curtis on Tokens in design systems](https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421).
### Token Hierarchy
Abyss uses a 3-tier token system:
- Core tier - the WHAT or the OPTIONS: contains primitive values, with no specific meaning - the name of the token and its raw value (HEX code for colors, and numbers for borders, corner radius, opacity, etc.)
- Semantic tier - the HOW or the DECISIONS: communicates design decisions on the exact usage of a Core token system-wide.
- Brand tokens - shorthand tokens to define common colors used throughout Abyss.
### Using Tokens
Before you can consume Abyss tokens, your project must be configured with our [themeProvider](/mobile/ui/theme-provider). This will allow you to access the tokens in your project.
Tokens are used in place of hard-coded values such as hex codes or pixels. To use a token, you can reference it in your code using the `$` symbol followed by the token name.
All Abyss components can accept tokens, when they are passed in using the `style`, or [styles](/mobile/developers/style-customization) prop. Non-Abyss components can use the [tokenize](/mobile/tools/tokenize) function to accept tokens.
#### Examples
Brand tokens are useful for quickly defining the color of components.
```jsx sandbox
```
#### Styled Function
To create a `View` component with a background color of `$core.color.brand.100`, you can leverage our [styled function](/mobile/tools/styled) and do the following:
```jsx sandbox
() => {
const Example = styled('View', {
backgroundColor: '$core.color.brand.100',
height: 100,
width: 100,
});
return ;
};
```
#### useToken hook
Alternatively, you can use our [useToken Hook](/mobile/hooks/use-token) to directly access the value of a token. This is useful when you need the value of multiple tokens.
```jsx sandbox
() => {
const getColorToken = useToken('colors');
const green = getColorToken('$core.color.green.100');
const red = getColorToken('$core.color.red.100');
return (
<>
>
);
};
```
#### Tokenize Function
Our [tokenize](/mobile/tools/tokenize) function is useful for mapping any non-Abyss component's props to accept Abyss tokens.
```jsx live
const TokenizedTouchableHighlight = tokenize(TouchableHighlight, {
underlayColor: 'colors',
});
render(() => {
return (
{}}
accessibilityRole="button"
>
Press Me
);
});
```
#### Useful Links
- [Custom Theme Tutorial](/mobile/developers/tutorials/custom-themes/): This tutorial will guide you through creating a custom Abyss theme for your project.
- [createTheme Function](/mobile/tools/create-theme): This tool allows you to create and modify themes to fit your design needs.
- [Theme Provider](/mobile/ui/theme-provider): Provider that passes the theme object down the component tree giving your project access to Abyss tokens.
- [styled Function](/mobile/tools/styled): Tool that allows you to create styled components.
- [useToken Hook](/mobile/hooks/use-token): Hook that allows you to access the value of a token in your project.
- [tokenize](/mobile/tools/tokenize): Function that allows you to map a component's props to accept Abyss tokens.
## Core Tokens
Below is a list of core tokens used throughout Abyss, These are split into the categories `color`, `border-width`, `border-radius`, `opacity`, `spacing`, `sizing`.
_**Note:** Click on the token row to copy the token to your clipboard._
#### Border Width Tokens
`border-width` tokens are used to define the `borderWidth` on components.
```jsx
const Example = styled('View', {
borderWidth: '$core.border-width.md',
});
```
```jsx render
```
#### Border Radius Tokens
`border-radius` tokens are used to define the `borderRadius` on components.
```jsx
const Example = styled('View', {
borderRadius: '$core.border-radius.md',
});
```
```jsx render
```
---
#### Opacity Tokens
`opacity` tokens are used to define the opacity of a component.
```jsx
const Example = styled('View', {
opacity: '$core.opacity.md',
});
```
```jsx render
```
---
#### Spacing Tokens
`spacing` tokens define the space between components. Generally, these are used for the `padding`, `margin`, or `gap` of components.
```jsx
const Example = styled('View', {
padding: '$core.spacing.200',
});
```
```jsx render
```
---
#### Sizing Tokens
`sizing` tokens define the size of components. Generally, these will be used to define the `width` or `height`.
```jsx
const Example = styled('View', {
width: '$core.sizing.600',
height: '$core.sizing.600',
});
```
```jsx render
```
---
#### Color Tokens
`color` tokens are used to define the color of components.
```jsx
const Example = styled('View', {
backgroundColor: '$core.color.brand.100',
});
```
```jsx render
```
## Brand Tokens
Brand tokens are useful for quickly defining the color of components.
_**Note:** Click on the token row to copy the token to your clipboard._
#### Colors
Below is a list of brand tokens and their intended use cases.
```jsx
const Example = styled('View', {
backgroundColor: '$primary1',
});
```
```jsx render
```
---
#### Spacing
`spacing` tokens define the space between components. Generally, these will be used to define the `padding`, `margin`, or `gap` of components.
```jsx
const Example = styled('View', {
padding: '$md',
});
```
```jsx render
```
---
#### Border Radius
`border-radius` tokens define the `borderRadius` on components.
```jsx
const Example = styled('View', {
borderRadius: '$md',
});
```
```jsx render
```
---
### Accessibility
Color choices that are accessible ensure everyone can not only see every element on a page but also understand a specific, intended meaning. You want everyone to be able to see the difference between two colors right next to or on top of each other.
Contrast refers to the perceived difference between foreground and background colors. People with low vision or color blindness and those with difficulty seeing the differences between colors can have trouble seeing where one element ends and another begins. As we age, the shape of our eyes changes and affects how we perceive color and how well we can distinguish color variations. If the contrast between different elements is too low, people may not be able to see them at all.
Contrast is expressed as a ratio with the first number representing the foreground color and the second representing the background color. For example, 3:1 means the foreground item color is three times more intense or visible than the background value. Contrast rules apply to text as well as any content that conveys meaning, including icons, graphics, and form elements. Tools such as Colour Contrast Analyzer or WebAIM's online color contrast tool are useful for verifying contrast ratios.
Color and contrast choices within a digital experience are accessible when people can:
- See UI elements and content
- Understand and interpret information
- Take action
We aim to provide a contrast ratio perceivable by all users. For this reason, UnitedHealthcare has embraced a minimum contrast ratio of 4.5:1 (foreground vs background) for UI elements and content that conveys meaning.
Recommendations
- Include color combinations, good contrast and poor contrast, in design documentation
- Communicate meaning with more than just color, such as with color and descriptive text
- Give focus indicators a unique presentation that meets contrast requirements on all backgrounds
Test for a minimum contrast ratio of 4.5 to 1 for:
- Non-bolded text smaller than 24 pixels (18 points)
- Bold text smaller than 18 pixels (14 points)
- Essential icons that are close to the body text size
Test that non-text elements that communicate information meet a minimum
contrast ratio of 3 to 1 for all states:
- Icons
- Data visualizations
- Focus indicators
- Controls, including their borders or boundaries
- Non-bolded text at or above 24 pixels (18 points)
- Bold text at or above 18 pixels (14 points)
Don't worry about contrast for logos and disabled elements. Watch out for using color alone to communicate meaning. People who are color blind or blind cannot perceive the meaning by color alone.
---
id: typography
title: Typography
category: Brand
description: Typography for UHC brands
---
## Overview
Typography is the art and technique of arranging type to make written language legible. In the Abyss library, [Heading](/mobile/ui/heading) and [Text](/mobile/ui/text) dive into the detail behind text formatting for UHC branding. More in depth guidance on typography can be found below and in the UHC Brand Page.
## Setting Global Fonts
Fonts can be set globally throughout an application by using the createTheme function in conjunction with the ThemeProvider component.
The second argument of createTheme function allows you to extend the base theme. Below is an example of setting a token named `customFont`.
```jsx
import { ThemeProvider } from '@uhg-abyss/mobile';
import { createTheme } from '@uhg-abyss/mobile';
const theme = createTheme('uhc', {
theme: {
fonts: {
customFont: 'RobotoFlex',
},
},
});
const App = () => {
return ...;
};
```
This would allow you to consume the font as a token globally.
```jsx
Filler Text
```
There are 2 tokens that are reserved for consumer usage: `$text` and `$heading`. Setting the tokens for these two will set the default font for the Text and Heading components globally.
If no font is set, the Text and Heading components will default to the system font.
```jsx
import { ThemeProvider } from '@uhg-abyss/mobile';
import { createTheme } from '@uhg-abyss/mobile';
const theme = createTheme('uhc', {
theme: {
fonts: {
heading: 'UHCSerif',
text: 'UHCSans',
},
},
});
const App = () => {
return ...;
};
```
## Headings
Headings identify chunks of related content on a page and establish the hierarchy showing how those chunks of content relate to each other. If someone reads only the headings on a page, they will get a general understanding of the information presented.
HTML defines six heading levels: H1 to H6.
H1 identifies an entire page, or overall topic, and is the most important level. There should only be 1 H1 per page.
Find further documentation in the [Heading](/mobile/ui/heading) component.
```jsx render
H | 1 | SemiBoldH | 2 | SemiBoldH | 3 | SemiBoldH | 4 | SemiBoldH | 5 | BoldH | 6 | Heavy
```
#### Recommendations
Always have an H1 heading for the page title
Keep headings scannable
Headings are always sentence-case
Do not use punctuation in headings
IMPORTANT: For way-finding, every page must have an H1 available (especially
for screen readers) that describes the main purpose of the page such as
“Claims & Benefits”
---
## Body Copy Text
SF Pro is our primary iOS typeface and Roboto is our primary Android typeface for body copy. All weights are available in italics.
Regular copy is the default style for the majority of text on pages. Small copy is the secondary style for context on pages and is used for secondary text styles, as well as footnotes and legal messaging or less important content. Find further documentation in the [Text Component](/web/ui/text).
```jsx render
() => {
const lorem =
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt.';
return (
P | LG | SemiBold
{lorem}
P | LG | Regular
{lorem}
P | MD | Bold
{lorem}
P | MD | SemiBold
{lorem}
P | MD | Regular
{lorem}
P | SM | Heavy
{lorem}
P | SM | Bold
{lorem}
P | SM | SemiBold
{lorem}
P | SM | Regular
{lorem}
P | XS | Bold
{lorem}
P | XS | SemiBold
{lorem}
P | XS | Medium
{lorem}
P | 2XS | SemiBold
{lorem}
P | 2XS | Medium
{lorem}
);
};
```
---
id: brandmark
category: Brand
title: Brandmark
description: Logos/Brandmarks for UHG brands.
design: 'https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/Abyss-Web?type=design&node-id=0-21&mode=design&t=uWtmzWwvT2Kv5MMG-0'
---
```jsx
import { Brandmark } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Brandmark',
inputs: [
{
prop: 'size',
type: 'string',
default: '$brandmark.sizing.lg'
},
{
prop: 'affiliate',
type: 'select',
options: [
{ label: 'uhg', value: 'uhg' },
],
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'lockup', value: 'lockup' },
]
},
{
prop: 'color',
type: 'select',
options: [
{ label: 'blue', value: 'blue' },
{ label: 'black', value: 'black' },
{ label: 'white', value: 'white' },
]
},
]
}
// Disclaimer: not all affiliate variant/color combinations are applicable, and inapplicable combinations will display as empty
```
## Brand
Use the `brand` property to adjust which brand is being selected.
```jsx live
```
## Size
Use the `size` property to adjust the size of the brandmark.
```jsx live
```
## Variant
Use the `variant` property to select the required brandmark variants.
```jsx live
```
## Color
Use the `color` property to select available brandmark colors.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
Brandmarks
```
You can use the search functionality to find the required brandmark. Brandmarks can be searched using their affiliates, variants or colors.
```jsx render
```
---
id: flat-list
category: Core
title: FlatList
description: A performant interface for rendering basic flat lists.
sourceIsTS: true
---
## Usage
The `FlatList` component is a high-performance list component that efficiently renders only the items currently
visible on the screen, regardless of the size of the data set. It is ideal for rendering basic, flat lists and
supports the most handy features like:
- Full tokenization support.
- Fully cross-platform.
- Optional horizontal mode.
- Configurable viewability callbacks.
- Header support.
- Footer support.
- Separator support.
- Pull to Refresh.
- Scroll loading.
- ScrollToIndex support.
- Multiple column support.
_If you need section support, consider using the [SectionList](/mobile/core/section-list) component._
```jsx live
const data = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'One',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Two',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Three',
},
{
id: '9b7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'Four',
},
{
id: '8ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Five',
},
{
id: '78694a0f-3da1-471f-bd96-145571e29d72',
title: 'Six',
},
{
id: '6b7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'Seven',
},
{
id: '5ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Eight',
},
];
const ItemWrapper = styled('View', {
width: '50%',
padding: '$md',
});
const ItemContainer = styled('View', {
backgroundColor: '$pastel1',
padding: '$md',
borderWidth: 4,
borderColor: '$interactive1',
alignItems: 'center',
borderRadius: '$lg',
});
const Category = styled('View', {
height: 50,
alignItems: 'center',
justifyContent: 'center',
});
const Item = ({ title }) => {
return (
{title}
);
};
render(() => {
return (
{
return ;
}}
keyExtractor={(item) => {
return item.id;
}}
numColumns={2}
ListHeaderComponent={
FlatList Header
}
ListHeaderComponentStyle={{
backgroundColor: '$interactive2',
borderColor: '$interactive1',
borderWidth: 6,
marginHorizontal: '$md',
borderRadius: '$lg',
}}
columnWrapperStyle={{
borderWidth: 6,
borderColor: '$interactive1',
marginVertical: '$xs',
backgroundColor: '$interactive2',
borderRadius: '$lg',
}}
contentContainerStyle={{ backgroundColor: '$gray1', padding: '$md' }}
ListFooterComponentStyle={{
backgroundColor: '$interactive2',
borderColor: '$interactive1',
borderWidth: 6,
marginHorizontal: '$md',
borderRadius: '$lg',
}}
ListFooterComponent={
FlatList Footer
}
/>
);
});
```
### Best Practices
- **Use Memoization:** Use [React.memo()](https://react.dev/reference/react/memo) to avoid unnecessary re-renders of list items.
- **Pagination:** For large datasets, implement pagination with `onEndReached` to load additional data dynamically.
- **Key Extraction:** Ensure `keyExtractor` returns a unique and stable key to avoid performance degradation caused by reordering or re-rendering items unnecessarily.
## Considerations
_`FlatList` is a convenience wrapper around [VirtualizedList](/mobile/core/virtualized-list), and thus inherits its props (as well as those of [ScrollView](/mobile/core/scroll-view)) that aren't explicitly listed here, along with the following caveats:_
- **Internal State:** Internal state is not preserved when content scrolls out of the render window. Ensure all your data is captured in the item data or external stores like Flux, Redux, or Relay.
- **Prop Updates:** This is a `PureComponent` meaning it will not re-render if props remain shallow-equal. Make sure that everything your `renderItem` function depends on is passed as a prop (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on changes. This includes the `data` prop and parent component state.
- **Item Rendering:** In order to constrain memory and enable smooth scrolling, content is rendered asynchronously offscreen. This means it's possible to scroll faster than the fill rate and momentarily see blank content. This is a tradeoff that can be adjusted to suit the needs of each application.
- **Key Management:** By default, the list looks for a `key` prop on each item and uses that for the React key. Alternatively, you can provide a custom `keyExtractor` prop.
### Accessibility Considerations
- **Screen Reader Support:** Ensure that list items have accessible labels and descriptions, especially if they contain interactive elements.
- **Focus Management:** When dynamically loading data, manage focus properly so users can navigate the list without losing track of their position.
### Performance Considerations
- **Windowing:** Use `initialNumToRender` and `maxToRenderPerBatch` props to control how many items are rendered initially and in each batch to avoid overloading the UI with too many items at once.
- **Recycling Cells:** Consider using `CellRenderComponent` to recycle rendered items and improve rendering performance for large lists.
- **Avoid Excessive Renders:** Leverage `shouldComponentUpdate` to prevent unnecessary renders of list items.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the FlatList component with design tokens',
},
{
name: 'hitSlop',
type: 'Insets',
description:
'This defines how far a touch event can start away from the FlatList',
},
{
name: 'contentContainerStyle',
type: 'Abyss.Style<"View">',
description:
'Object or array of objects defining the style of the content container within the FlatList component with design tokens. These styles will be applied to the FlatList content container which wraps all of the child views',
},
{
name: 'contentInset',
type: 'Insets',
description:
'The amount by which the FlatList content is inset from the edges of the FlatList',
},
{
name: 'endFillColor',
type: 'Abyss.Color',
description:
'The color of the background of the list when there are not enough items to fill the content',
},
{
name: 'ListFooterComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListFooterComponent. Accepts an object or array of objects which defines the style of the ListFooterComponent within the FlatList component with design tokens',
},
{
name: 'ListHeaderComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListHeaderComponent. Accepts an object or array of objects which defines the style of the ListFooterComponent within the FlatList component with design tokens',
},
{
name: 'columnWrapperStyle',
type: 'Abyss.Style<"View">',
description:
'Optional custom style for multi-item rows generated when `numColumns > 1`. Accepts an object or array of objects which defines the style of the column wrapper within the FlatList component with design tokens',
},
]}
/>
```
---
id: image
category: Core
title: Image
description: Displays different types of images, including network images, static resources, temporary local images, and images from local disk, such as the camera roll.
sourceIsTS: true
---
```jsx
import { Image } from '@uhg-abyss/mobile';
```
## Usage
The Image component is a fundamental UI element that displays images in your application.
This component is a customized extension of React Native's `Image` component, which is enhanced to
fit seamlessly within our design system. It supports various image formats, allows for custom
styling, and includes optimizations for loading performance.
```jsx render
Note that for network and data images, you will need to manually specify the
dimensions of your image!
```
```jsx live-expanded
```
You can also use the `style` prop with custom design tokens to style the image.
```jsx live
```
## GIF and WebP support on Android
When building your own native code, GIF and WebP are not supported by default on Android.
You will need to add some optional modules in `android/app/build.gradle`, depending on the needs of your app.
```
dependencies {
// If your app supports Android versions before Ice Cream Sandwich (API level 14)
implementation 'com.facebook.fresco:animated-base-support:1.3.0'
// For animated GIF support
implementation 'com.facebook.fresco:animated-gif:3.1.3'
// For WebP support, including animated WebP
implementation 'com.facebook.fresco:animated-webp:3.1.3'
implementation 'com.facebook.fresco:webpsupport:3.1.3'
// For WebP support, without animations
implementation 'com.facebook.fresco:webpsupport:3.1.3'
}
```
## Best Practices
- **Use Accessibility Label:** Provide meaningful accessibility labels for accessibility. This is especially important for images that convey important information.
- **Optimize Images:** Use appropriately sized images to reduce load times and improve performance. Compress images and use formats that balance quality and file size.
- **Minimize Re-Renders:** Avoid unnecessary re-renders of the Image component, especially for large or high-resolution images.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the Image component with design tokens.',
},
{
name: 'capInsets',
type: 'Insets',
description:
'When the image is resized, the corners of the size specified by `capInsets` will stay a fixed size, but the center content and borders of the image will not be stretched.',
},
{
name: 'height',
type: 'Abyss.Size',
description: 'Height of the image.',
},
{
name: 'width',
type: 'Abyss.Size',
description: 'Width of the image.',
},
{
name: 'tintColor',
type: 'Abyss.Color',
description:
'Changes the color of all non-transparent pixels to the `tintColor`.',
},
]}
/>
```
---
id: image-background
category: Core
title: ImageBackground
description: Display an image as the background of another component.
sourceIsTS: true
---
```jsx
import { ImageBackground } from '@uhg-abyss/mobile';
```
## Usage
A common feature request from developers familiar with the web is a `background-image`. To handle this use case, you can use the
`ImageBackground` component, which has the same props as `Image`, and add whatever children to it you would like to layer on top of it.
The `ImageBackground` component is a specialized container that displays an image as the background of a view.
This component is an enhancement of React Native's core `ImageBackground`, tailored to integrate seamlessly with our design system.
## Example
```jsx live
Inside
```
## Resize Mode
The `resizeMode` prop controls how the image is resized within the bounds set by the `style` prop. It can be one of the following values:
```jsx live
() => {
const [mode, setMode] = useState('cover');
const changeMode = (newMode) => {
return () => setMode(newMode);
};
const modes = ['cover', 'contain', 'stretch', 'repeat', 'center'];
return (
Abyss
{modes.map((m) => {
return (
);
})}
);
};
```
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the ImageBackground component with design tokens.',
},
{
name: 'capInsets',
type: 'Insets',
description:
'When the image is resized, the corners of the size specified by `capInsets` will stay a fixed size, but the center content and borders of the image will not be stretched.',
},
{
name: 'height',
type: 'Abyss.Size',
description: 'Height of the image.',
},
{
name: 'width',
type: 'Abyss.Size',
description: 'Width of the image.',
},
{
name: 'tintColor',
type: 'Abyss.Color',
description:
'Changes the color of all non-transparent pixels to the `tintColor`.',
},
{
name: 'imageStyle',
type: 'Abyss.Style<"Image">',
description:
'Object or array of objects defining the style of the Image component within the ImageBackground component with design tokens.',
},
]}
/>
```
---
id: keyboard-avoiding-view
category: Core
title: KeyboardAvoidingView
description: Automatically adjust its height, position, or bottom padding based on the keyboard height to remain visible while the virtual keyboard is displayed.
sourceIsTS: true
---
```jsx
import { KeyboardAvoidingView } from '@uhg-abyss/mobile';
```
## Usage
The `KeyboardAvoidingView` component is designed to automatically adjust the layout of your application
when the on-screen keyboard appears, ensuring that the content remains visible and accessible to the user.
This component extends the `KeyboardAvoidingView` core component present in React Native, while also supporting tokens
in the `style`, `contentContainerStyle`, and `keyboardVerticalOffset` props.
```jsx
() => {
const [value, setValue] = useState('');
return (
Press the Input
);
};
const styles = StyleSheet.create({
heading: {
marginBottom: '$sm',
},
innerView: {
padding: 24,
flex: 1,
justifyContent: 'space-between',
},
code: {
backgroundColor: '$gray1',
lineHeight: '$md',
fontSize: '$sm',
fontWeight: '$bold',
},
});
```
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the KeyboardAvoidingView component with design tokens.',
},
{
name: 'contentContainerStyle',
type: 'Abyss.Style<"View">',
description:
'Style object for the content container within the KeyboardAvoidingView.',
},
{
name: 'keyboardVerticalOffset',
type: 'Abyss.Space',
description: 'The distance between the keyboard and the view.',
},
]}
/>
```
---
id: keyboard-aware-scroll-view
category: Core
title: KeyboardAwareScrollView
description: A ScrollView component that automatically handles keyboard appearance and scrolls to focused TextInput.
sourceIsTS: true
---
```jsx
import { KeyboardAwareScrollView } from '@uhg-abyss/mobile';
```
## Usage
The `KeyboardAwareScrollView` component is a wrapper around [this package's](https://www.npmjs.com/package/react-native-keyboard-aware-scroll-view) `KeyboardAwareScrollView` component that automatically adjusts its content when the keyboard appears. It's particularly useful for forms and other input-heavy screens where you want to ensure that the focused input remains visible when the keyboard is shown.
```jsx
() => {
const [value1, setValue1] = useState('');
const [value2, setValue2] = useState('');
return (
Form Example
);
};
```
## Platform Differences
- On iOS, the component uses `react-native-keyboard-aware-scroll-view` which provides smooth keyboard handling.
- On Android, it falls back to the native `ScrollView` with basic keyboard handling.
```jsx render
```
```jsx render
```
---
id: pressable
category: Core
title: Pressable
description: A pressable component wrapper that can be used to provide touch feedback.
sourceIsTS: true
---
## Usage
Pressable is a Core Component that can detect various stages of press interactions on any of its defined children.
```jsx
I'm pressable!
```
### How It Works
**On an element wrapped by Pressable:**
- [onPressIn](https://reactnative.dev/docs/pressable#onpressin) is called when a press is activated.
- [onPressOut](https://reactnative.dev/docs/pressable#onpressout) is called when the press gesture is deactivated.
**After onPressIn, the user will either:**
- Remove their finger, triggering [onPressOut](https://reactnative.dev/docs/pressable#onpressout) followed
by [onPress](https://reactnative.dev/docs/pressable#onpress).
- Hold their finger longer than 500 milliseconds before removing it, [onLongPress](https://reactnative.dev/docs/pressable#onlongpress)
is triggered. _([onPressOut](https://reactnative.dev/docs/pressable#onpressout) will still fire when they remove their finger)_.
Diagram from React Native Documentation
```jsx render
The touch area never extends past the parent view bounds and the Z-index of
sibling views always takes precedence if a touch hits two overlapping views.
```
### HitRect & HitSlop
Fingers are not the most precise instruments, and it is common for users to accidentally activate the wrong element or miss
the activation area. To help, `Pressable` has an optional `HitRect` you can use to define how far a touch can register away from
the wrapped element. Presses can start anywhere within a `HitRect`.
`PressRect` allows presses to move beyond the element and its `HitRect` while maintaining activation and being eligible for a
"press"—think of sliding your finger slowly away from a button you're pressing down on.
Diagram from React Native Documentation
_You can set `HitRect` with `hitSlop` and set `PressRect` with `pressRetentionOffset`_.
```jsx render
Pressable uses React Native's Pressability API. For
more information around the state machine flow of Pressability and how it
works, check out the implementation for
Pressability
.
```
### Styling
The `style` prop can be a function, an array of objects, or an object that defines the style of the `Pressable` component with design tokens.
When using a function, the function will receive the `pressed` state as an argument.
Additionally, the `children` prop can be a function that receives the `pressed` state as an argument or a React element.
```jsx live
{
return {
width: 125,
height: 125,
borderWidth: pressed ? 10 : 4,
borderRadius: '$xl',
borderColor: pressed ? '$success1' : '$error3',
backgroundColor: pressed ? '$success2' : '$error2',
margin: '$md',
padding: '$sm',
alignItems: 'center',
justifyContent: 'center',
};
}}
onPress={() => console.log('onPress Called!')}
onPressIn={() => console.log('onPressIn Called!')}
onPressOut={() => console.log('onPressOut Called!')}
onLongPress={() => console.log('onLongPress Called!')}
>
{({ pressed }) => (
{pressed ? 'Release Me' : 'Press Me'}
)}
```
### Best Practices
- **Press Feedback:** Always provide clear visual feedback (like color changes or animations) to indicate the element has been pressed.
- **Hit Slop:** Use the `hitSlop` prop to extend the touchable area if needed, especially for smaller elements.
- **Optimize Press Timing**: Use `onPressIn` and `onPressOut` wisely to handle animations or delays without affecting user experience.
## Accessibility Considerations
- **Pressable Texts:** Ensure that the label of the pressable is descriptive for screen readers.
- **Feedback for Press**: Make sure the visual feedback is discernible for all users, including those with visual impairments.
- **Keyboard Navigation:** Ensure that pressable components are focusable and navigable with a keyboard.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the Pressable component with design tokens',
},
{
name: 'hitSlop',
type: 'Inset | Insets',
description:
'This defines how far a touch event can start away from the view.',
},
{
name: 'pressRetentionOffset',
type: 'Inset | Insets',
description:
'Additional distance outside of this view in which a touch is considered a press before `onPressOut` is triggered.',
},
]}
/>
```
```
---
id: refresh-control
category: Core
title: RefreshControl
description: A standard control that can initiate the refreshing of a scroll view's contents
sourceIsTS: true
---
```jsx
import { RefreshControl } from '@uhg-abyss/mobile';
```
## Usage
The `RefreshControl` component is used to implement pull-to-refresh functionality in scrollable views,
such as `ScrollView`, `FlatList`, or `SectionList`. This component is a customized version of React
Native's core RefreshControl, offering enhanced styling, animations, and better integration with our
design system.
```jsx render
Note: refreshing is a controlled prop, which is why it needs to
be set to true in the onRefresh function otherwise the refresh
indicator will stop immediately.
```
```jsx
() => {
const [refreshing, setRefreshing] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setRefreshing(false);
}, 4500);
}, []);
return (
}
>
Pull down to see RefreshControl indicator
);
};
```
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the RefreshControl component',
},
{
name: 'colors',
type: 'Abyss.Color[]',
description:
'The colors (at least one) that will be used to draw the refresh indicator',
},
{
name: 'progressBackgroundColor',
type: 'Abyss.Color',
description: 'The background color of the refresh indicator',
},
{
name: 'tintColor',
type: 'Abyss.Color',
description: 'The tint color of the refresh indicator',
},
{
name: 'titleColor',
type: 'string',
description: 'The color of the refresh indicator title',
},
{
name: 'progressViewOffset',
type: 'number',
description:
'The distance between the refresh indicator and the top of the view',
},
]}
/>
```
---
id: safe-area-view
category: Core
title: SafeAreaView
description: Render content within the safe area boundaries of a device.
sourceIsTS: true
---
```jsx
import { SafeAreaView } from '@uhg-abyss/mobile';
```
## Usage
The purpose of `SafeAreaView` is to render content within the safe area boundaries of a device.
It is currently only applicable to iOS devices with iOS version 11 or later.
`SafeAreaView` renders nested content and automatically applies padding to reflect the portion
of the view that is not covered by navigation bars, tab bars, toolbars, and other ancestor
views. Moreover, and most importantly, Safe Area's paddings reflect the physical limitation
of the screen, such as rounded corners or camera notches (i.e. the sensor housing area on iPhone 13).
```jsx
This is a SafeAreaView that avoids the Status Bar
This is a SafeAreaView that avoids the Home Bar
```
```jsx render:phone-dark
const Container = styled('View', {
justifyContent: 'space-between',
width: '100%',
});
const PaddedView = styled('View', {
paddingHorizontal: '$md',
backgroundColor: '$primary1',
width: '100%',
variants: {
placement: {
top: {
paddingTop: 40,
paddingBottom: '$md',
},
bottom: {
paddingBottom: 28,
paddingTop: '$md',
},
},
},
});
const Label = styled('Text', {
color: '$white',
fontSize: '$md',
textAlign: 'center',
});
render(() => {
return (
);
});
```
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the SafeAreaView component with design tokens.',
},
]}
/>
```
```jsx render
As padding is used to implement the behavior of the component, padding rules
in styles applied to a SafeAreaView will be ignored and can cause
different results depending on the platform. See{' '}
#22211
{' '}
for details.
```
---
id: scroll-view
category: Core
title: ScrollView
description: A generic scrolling container that can host multiple components and views.
sourceIsTS: true
---
## Usage
The `ScrollView` component is a scrollable container that can hold a variety of elements,
enabling vertical or horizontal scrolling. This customized version of React Native's [ScrollView](https://reactnative.dev/docs/scrollview)
component integrates Abyss design tokens and performance optimizations for a smooth and responsive experience.
```jsx live
Scroll Me
Lorem ipsum odor amet, consectetuer adipiscing elit. Elit lacinia torquent
et mauris habitasse netus efficitur aenean aptent. Finibus posuere maximus
tortor, nisi bibendum ultricies. Tellus integer eu commodo sed pharetra
mauris quam potenti mauris. Convallis nisl auctor risus mattis id. Himenaeos
turpis egestas consequat tortor aliquam, dictumst integer volutpat eu. Quis
leo ex parturient arcu sagittis. Et nostra platea vestibulum bibendum
pharetra accumsan semper cursus.
{'\n'}
{'\n'}
Dictum porttitor penatibus auctor nisl; sem porttitor curae quisque. Ipsum accumsan
eu vestibulum ligula, vehicula integer. Nunc varius massa placerat conubia mus
magna. Aliquet eleifend porttitor porta mattis consectetur habitasse at fringilla.
Odio aptent aliquam sociosqu justo egestas adipiscing ac conubia. Bibendum ultrices
commodo ante mus mollis netus.
{'\n'}
{'\n'}
Bibendum taciti habitant ridiculus scelerisque aliquam varius lacus maximus.
Efficitur facilisis parturient auctor accumsan nascetur ad phasellus lectus.
Lacinia natoque conubia convallis habitant mauris eleifend. Turpis
consectetur tempor egestas taciti; venenatis cursus? Cursus congue
adipiscing purus neque vitae nibh? Risus accumsan ullamcorper velit eros
tellus curae. Interdum nascetur morbi; pharetra id venenatis volutpat
potenti. Convallis senectus praesent lectus nisi eget justo vitae. Venenatis
ornare sociosqu euismod feugiat integer. Curae odio massa purus eu facilisis
laoreet.
{'\n'}
{'\n'}
Lectus curabitur scelerisque mus auctor nascetur iaculis ante risus. Tristique
conubia nisl inceptos bibendum pellentesque. Eleifend imperdiet gravida pellentesque
hendrerit eget dignissim magnis varius augue. Curabitur proin porttitor molestie
gravida amet praesent et fringilla. Ante etiam at gravida efficitur cubilia rutrum
torquent adipiscing. Parturient bibendum id convallis torquent venenatis. Lacinia
primis leo nullam tincidunt consectetur quisque. Elementum tristique quis magnis
ornare molestie venenatis. Sollicitudin netus class rutrum proin; curabitur facilisis
convallis pretium sollicitudin. Feugiat volutpat eget arcu convallis ultricies
id.
```
### ScrollView vs FlatList
`ScrollView` renders all its child components all at once, even if the component is not in view.
This can negatively affect the performance of the app by requiring more processing power and memory usage when rendering a large number of items.
This is where [FlatList](/mobile/core/flat-list) comes into play. `FlatList` renders items lazily, before they
appear on screen. It also removes items that scroll off-screen to save memory and processing time.
`FlatList` is also handy if you want to render separators between your items, multiple columns,
infinite scrolling, or any number of other features it supports out of the box.
### Best Practices
- **Minimize Overdraw:** Use a background color to avoid unnecessary redrawing of background elements.
- **Limit Scrollable Content:** Avoid putting too many elements inside a `ScrollView`. If the content grows large, consider using a `FlatList` or `SectionList` for better performance.
- **Optimize Images:** When scrolling with images, ensure they are properly sized and optimized to prevent memory issues.
## Considerations
- **Bounded Height:** The `ScrollView` must have a bounded height, since they contain children with unbound-heights.
- To set the height of a `ScrollView`, either define a height directly (discouraged) or make sure the parent Components have bounded height.
- **Nested Responders:** `ScrollView` does not yet support preventing touch gestures on its children from becoming scroll gestures.
- This doesn't mean that responders won't work inside of a `ScrollView`. It simply means `ScrollView` will prioritize its own responder if it detects a gesture that could be interpretedas a scroll.
- _*For more information, check out React Native's [Gesture Responder System](https://reactnative.dev/docs/gesture-responder-system).*_
### Accessibility Considerations
- **Keyboard Focus:** Ensure that the content inside the `ScrollView` is reachable and visible when users navigate with a keyboard.
- **Readable Labels:** Label any scrollable area for screen readers, so users know they can scroll through the content.
- **Scroll Indicators:** Allow scroll indicators to be visible for accessibility users, so they are aware of the scrollable content.
### Performance Considerations
- **Rendering Limits:** Avoid placing too many child components inside a `ScrollView` as it can cause performance bottlenecks. Instead, use lists (`FlatList`,`SectionList`) for large datasets.
- **Lazy Loading:** Consider lazy loading for content-heavy views to avoid loading everything upfront.
- **Batch Updates:** Ensure updates to the scroll view content are batched to reduce rendering overhead.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the ScrollView component with design tokens',
},
{
name: 'contentContainerStyle',
type: 'Abyss.Style<"View">',
description:
'Object or array of objects defining the style of the content container within the ScrollView component with design tokens. These styles will be applied to the scroll view content container which wraps all of the child views',
},
{
name: 'contentInset',
type: 'Insets',
description:
'The amount by which the scroll view content is inset from the edges of the scroll view',
},
{
name: 'hitSlop',
type: 'Insets',
description:
'This defines how far a touch event can start away from the ScrollView',
},
{
name: 'endFillColor',
type: 'Abyss.Color',
description:
'Sometimes a scrollview takes up more space than its content fills. When this is the case, this prop will fill the rest of the scrollview with a color to avoid setting a background and creating unnecessary overdraw. This is an advanced optimization that is not needed in the general case',
},
]}
/>
```
---
id: section-list
category: Core
title: SectionList
description: A performant interface for rendering sectioned lists.
sourceIsTS: true
---
## Usage
The `SectionList` component is a high-performance list component that efficiently renders sectioned lists. It is ideal for rendering lists with sections and supports the most handy features like:
- Full tokenization support.
- Fully cross-platform.
- Configurable viewability callbacks.
- List header support.
- List footer support.
- Item separator support.
- Section header support.
- Section separator support.
- Heterogeneous data and item rendering support.
- Pull to Refresh.
- Scroll loading.
_If you don't need section support and want a simpler interface, use a [FlatList](/mobile/core/flat-list)._
```jsx live
const data = [
{
title: 'Main Dishes',
data: ['Pizza', 'Burger', 'Risotto'],
},
{
title: 'Sides',
data: ['French Fries', 'Onion Rings', 'Fried Shrimps'],
},
{
title: 'Drinks',
data: ['Water', 'Coke', 'Beer'],
},
{
title: 'Desserts',
data: ['Cheese Cake', 'Ice Cream', 'Brownies'],
},
];
const Item = styled('Text', {
backgroundColor: '$interactive3',
padding: '$md',
marginVertical: '$xs',
fontSize: '$xl',
color: '$primary1',
borderWidth: 2.5,
borderColor: '$primary1',
});
render(() => {
return (
{
return item + index;
}}
renderItem={({ item }) => {
return {item};
}}
renderSectionHeader={({ section: { title } }) => {
return {title};
}}
contentContainerStyle={{ padding: '$md' }}
/>
);
});
```
### Best Practices
- **Use Memoization:** Use [React.memo()](https://react.dev/reference/react/memo) to avoid unnecessary re-renders of list items.
- **Section Headers:** Keep section headers concise to avoid taking up too much space.
- **Key Management:** Ensure that the `keyExtractor` for individual items and sections is unique to avoid rerender issues.
## Considerations
_`SectionList` is a convenience wrapper around [VirtualizedList](/mobile/core/virtualized-list), and thus inherits its props (as well as those of [ScrollView](/mobile/core/scroll-view)) that aren't explicitly listed here, along with the following caveats:_
- **Internal State:** Internal state is not preserved when content scrolls out of the render window. Ensure all your data is captured in the item data or external stores like Flux, Redux, or Relay.
- **Prop Updates:** This is a `PureComponent` meaning it will not re-render if props remain shallow-equal. Make sure that everything your `renderItem` function depends on is passed as a prop (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on changes. This includes the `data` prop and parent component state.
- **Item Rendering:** In order to constrain memory and enable smooth scrolling, content is rendered asynchronously offscreen. This means it's possible to scroll faster than the fill rate and momentarily see blank content. This is a tradeoff that can be adjusted to suit the needs of each application.
- **Key Management:** By default, the list looks for a `key` prop on each item and uses that for the React key. Alternatively, you can provide a custom `keyExtractor` prop.
### Accessibility Considerations
- **Navigable Sections:** Ensure section headers and items are properly labeled for screen readers.
- **Focus Management:** When rendering additional sections, ensure the user focus remains consistent without jumping or losing context.
### Performance Considerations
- **Batch Updates:** Use batch updates to avoid triggering multiple re-renders when updating section data.
- **SectionHeader Optimization:** Memoize section headers to prevent unnecessary re-renders during list scrolls.
- **Windowing:** Use `initialNumToRender` and `maxToRenderPerBatch` props to control how many items are rendered initially and in each batch to avoid overloading the UI with too many items at once.
- **Recycling Cells:** Consider using `CellRenderComponent` to recycle rendered items and improve rendering performance for large lists.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the SectionList component with design tokens',
},
{
name: 'hitSlop',
type: 'Insets',
description:
'This defines how far a touch event can start away from the SectionList',
},
{
name: 'contentContainerStyle',
type: 'Abyss.Style<"View">',
description:
'Object or array of objects defining the style of the content container within the SectionList component with design tokens. These styles will be applied to the scroll view content container which wraps all of the child views',
},
{
name: 'contentInset',
type: 'Insets',
description:
'The amount by which the scroll view content is inset from the edges of the scroll view',
},
{
name: 'endFillColor',
type: 'Abyss.Color',
description:
'The color of the background of the SectionList when there are not enough items to fill the content',
},
{
name: 'ListFooterComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListFooterComponent. Accepts an object or array of objects which defines the style of the ListFooterComponent within the FlatList component with design tokens',
},
{
name: 'ListHeaderComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListHeaderComponent. Accepts an object or array of objects which defines the style of the ListHeaderComponent within the FlatList component with design tokens',
},
]}
/>
```
---
id: status-bar
category: Core
title: StatusBar
description: Component to control the app's status bar.
sourceIsTS: true
---
```jsx
import { StatusBar } from '@uhg-abyss/mobile';
```
## Usage
The `StatusBar` component controls the app's status bar. The status bar is the zone, typically at the top of
the screen, that displays the current time, Wi-Fi and cellular network information, battery level
and/or other status icons.
This component is a customized version of React Native's `StatusBar` core component, offering additional configuration
options and integration with our design system. It allows you to manage the status bar's `style`, `visibility`, and `backgroundColor`
to match the application's theme with our design tokens.
## Usage with Navigator
It is possible to have multiple StatusBar components mounted at the same time. The props will
be merged in the order the StatusBar components were mounted.
## Imperative API
For cases where using a component is not ideal, there is also an imperative API exposed as
static functions on the component. However, it is not recommended to use the static API and the
component for the same prop because any value set by the static API will get overridden by the one
set by the component in the next render.
## Performance Considerations
The StatusBar is a lightweight component, but to ensure optimal performance:
- **Minimize Dynamic Changes:** Limit frequent updates to the status bar's properties, as unnecessary changes
can impact performance, especially on lower-end devices.
- **Use Animations Judiciously:** While animations can enhance the user experience, use them sparingly to
avoid performance degradation.
## Accessibility Considerations
When configuring the StatusBar, ensure that the chosen colors and styles provide sufficient contrast
and readability. The status bar should be easily readable in various lighting conditions and should not
obscure critical content or UI elements.
```jsx render
```
```jsx render
```
---
id: touchable-highlight
category: Core
title: TouchableHighlight
description: A wrapper for making views respond properly to touches.
sourceIsTS: true
---
```jsx render
If you're looking for a more extensive and future-proof way to handle
touch-based input, check out the
Pressable
API.
```
## Usage
`TouchableHighlight` is a wrapper for handling pressEvents of a `View`. While pressing down, the opacity of the wrapped view
is decreased, allowing the underlay color to show through.
```jsx
function MyComponent(props: MyComponentProps) {
return (
My Component
);
}
alert('Pressed!')}
>
;
```
```jsx live
render(() => {
return (
{}}
>
Gray Touchable Highlight
);
});
```
## Considerations
- **Visual Artifacts:** The underlay comes from wrapping the child in a `View` component. This can sometimes cause unwanted visual artifacts and affect layout if not used correctly.
For example, if the `backgroundColor` of the wrapped `View` is not explicitly set to an opaque color.
- **Children:** `TouchableHighlight` can only have a single child. If you wish to have several children, wrap them in a `View`.
### Accessibility Considerations
- **Feedback for Users:** Ensure that the visual feedback (`underlayColor` color) is noticeable for users with visual impairments.
- **Screen Reader Support:** Label the component appropriately for screen readers so users understand the interaction.
- **Keyboard Focus:** Ensure the component can be focused and activated using a keyboard for accessibility.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the TouchableHighlight component with design tokens',
},
{
name: 'hitSlop',
type: 'Inset | Insets',
description:
'This defines how far a touch event can start away from the view',
},
{
name: 'pressRetentionOffset',
type: 'Inset | Insets',
description:
'Additional distance outside of this view in which a touch is considered a press before `onPressOut` is triggered',
},
{
name: 'underlayColor',
type: 'Abyss.Color',
description:
'The color of the underlay that will show through when the touch is active',
},
{
name: 'activeOpacity',
type: 'Abyss.Opacity',
description:
'Defines what the opacity of the wrapped view should be when touch is active',
},
]}
/>
```
---
id: touchable-opacity
category: Core
title: TouchableOpacity
description: A wrapper for making views respond properly to touches.
sourceIsTS: true
---
```jsx render
If you're looking for a more extensive and future-proof way to handle
touch-based input, check out the{' '}
Pressable
{' '}
API.
```
## Usage
The `TouchableOpacity` component is used to create pressable elements that fade out on press,
providing smooth and subtle visual feedback. This component is lightweight and often used for
buttons or other pressable elements that require an opacity change on interaction. This customized
version of the React Native `TouchableOpacity` component is enhanced to supports Abyss design tokens and fit seamlessly into our design system.
Opacity is controlled by wrapping the children in an `Animated.View`, which is added to the view
hierarchy. Be aware that this can affect layout.
```jsx live
const styles = StyleSheet.create({
button: {
borderWidth: 2,
padding: '$md',
alignItems: 'center',
borderRadius: 100,
borderColor: '$info1',
backgroundColor: '$conditional2',
},
});
render(() => {
return (
Opacity Button
);
});
```
### Best Practices
- **Consistent Opacity:** Use consistent values for activeOpacity across your app to maintain uniformity in user interactions.
- **Clear Press Feedback:** Ensure that the change in opacity is noticeable enough to signal to users that the element is pressed.
- **Layering Components:** Be mindful when layering TouchableOpacity over complex backgrounds, as the fade effect might not be as visible.
## Accessibility Considerations
- **Visual Feedback:** Ensure the fade effect is sufficiently noticeable for all users, especially those with visual impairments.
- **Keyboard Navigation:** Ensure the component can be navigated and activated via a keyboard.
- **Accessible Labels:** Add descriptive labels to the TouchableOpacity component so screen readers can convey its functionality.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the TouchableOpacity component with design tokens',
},
]}
/>
```
---
id: touchable-without-feedback
category: Core
title: TouchableWithoutFeedback
description: Captures touch events without providing any visual feedback.
sourceIsTS: true
---
```jsx render
If you're looking for a more extensive and future-proof way to handle
touch-based input, check out the
Pressable
API.
```
## Usage
The `TouchableWithoutFeedback` component is a wrapper that captures touch events without providing any visual feedback.
It is ideal for handling touch events on components that don't need to display any visual feedback.
**Do not use unless you have a very good reason.** All elements that respond to press should have a visual feedback when touched.
```tsx
function MyComponent(props: MyComponentProps) {
return (
My Component
);
}
alert('Pressed!')}>
;
```
### Example
```jsx live
() => {
const Container = styled('View', {
flex: 1,
justifyContent: 'center',
paddingHorizontal: '$md',
});
const CountContainer = styled('View', {
alignItems: 'center',
padding: '$md',
});
const Count = styled('Text', {
color: '$interactive1',
});
const ButtonView = styled('View', {
alignItems: 'center',
backgroundColor: '$gray2',
padding: '$sm',
});
const [count, setCount] = useState(0);
const handlePress = () => {
setCount(count + 1);
};
return (
Count: {count}Increment
);
};
```
### Best Practices
- **Use Sparingly:** Only use `TouchableWithoutFeedback` when no visual feedback is required or desired.
If feedback is expected, use `Pressable` or `TouchableOpacity` instead.
- **Visual Feedback:** Ensure the child components provide sufficient visual feedback, even if `TouchableWithoutFeedback` does not.
- **Invisible Buttons:** Consider accessibility implications if `TouchableWithoutFeedback` is used to
create invisible or hidden touch areas.
## Considerations
- **Number of Children:** `TouchableWithoutFeedback` only supports one child. If you wish to have several child components, wrap them in a View.
- **Prop Spread:** `TouchableWithoutFeedback` Does not handle touch events directly, it clones its child and applies responder props to the clone.
Therefore it is important that any intermediary components pass props through to the underlying React Native component.
### Accessibility Considerations
- **Keyboard Navigation:** Ensure the component is accessible via keyboard and focusable if needed.
- **Screen Reader Labels:** If touchable areas are hidden or provide no feedback, ensure the interactive
area is described accurately for screen readers.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the TouchableWithoutFeedback component with design token support.',
},
{
name: 'hitSlop',
type: 'Inset | Insets',
description:
'This defines how far a touch event can start away from the view.',
},
{
name: 'pressRetentionOffset',
type: 'Inset | Insets',
description:
'Additional distance outside of this view in which a touch is considered a press before `onPressOut` is triggered.',
},
]}
/>
```
```
---
id: view
category: Core
title: View
description: The most fundamental core component for building a UI, a container that supports layout.
sourceIsTS: true
---
```jsx
import { View } from '@uhg-abyss/mobile';
```
## Usage
The `View` component is one of the fundamental building blocks of a user interface. It functions as a
container that supports layout, styling, and interaction handling. The component serves as a versatile
wrapper for organizing and displaying other components within a user interface.
While it extends the core View component present in React Native, the `View` component in Abyss Mobile
allows using tokens directly in the style prop. This feature enables developers to use the design tokens
defined in the theme to style a component.
This example creates a View that wraps two boxes with color and a text component in a row with padding.
Notice the use of design tokens in the style prop.
```jsx live
Hello World!
```
```jsx render
Views are designed to be used with{' '}
StyleSheet for clarity and performance,
although inline styles are also supported.
```
## Best Practices
- **Use for Layout**: Utilize the `View` component to create layouts and organize components within a user interface. For
text context, consider using the [Text component](/mobile/ui/text).
- **Avoid Excessive Nesting**: Limit the number of nested `View` components to maintain a clean and efficient layout.
- **Use Tokens**: Leverage design tokens in the style prop to ensure consistency and maintainability in styling.
- **Accessibility**: Ensure that the content within the `View` component is accessible to all users by providing
appropriate labels and descriptions where necessary.
## Performance Considerations
To maximize performance, be mindful of:
- **Shallow component trees**: Minimize nesting `View` components to reduce the complexity of the component tree.
- **Avoid unnecessary re-renders**: Use `React.memo` or similar optimization when rendering complex or frequently changing layouts.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the View component with design tokens.',
},
]}
/>
```
---
id: virtualized-list
category: Core
title: VirtualizedList
description: A high-performance list component that efficiently renders only the items currently visible on the screen, regardless of the size of the data set.
sourceIsTS: true
---
## Usage
The `VirtualizedList` component is a high-performance list component that efficiently renders only the items currently
visible on the screen, regardless of the size of the data set.
This is the base implementation of the [FlatList](/mobile/core/flat-list) and [SectionList](/mobile/core/section-list) components. In general,
this should only be used if you need more flexibility than FlatList or SectionList can provides, e.g. for use with immutable data instead of plain arrays.
Virtualization massively improves the performance and memory consumption of large lists by maintaining a finite render window showing only active
items and replacing all items outside of the render window with appropriately sized blank space. The render window adapts with scrolling behavior,
items are rendered incrementally with _low-pri_ (after any running interactions) if they are far from the visible area, or with _hi-pri_ if they are near the visible area.
```jsx live
const ItemContainer = styled('View', {
backgroundColor: '$conditional3',
height: 150,
justifyContent: 'center',
marginVertical: '$sm',
marginHorizontal: '$md',
padding: 20,
});
const ItemText = styled('Text', {
fontSize: 32,
});
const Item = ({ title }) => {
return (
{title}
);
};
const getItem = (_data, index) => {
return {
id: Math.random().toString(12).substring(0),
title: `Item ${index + 1}`,
};
};
render(() => {
return (
{
return ;
}}
keyExtractor={(item) => {
return item.id;
}}
getItemCount={() => {
return 50;
}}
getItem={getItem}
ListFooterComponent={}
ListHeaderComponent={}
ListHeaderComponentStyle={{
borderColor: '$conditional3',
borderWidth: 4,
marginHorizontal: '$md',
}}
ListFooterComponentStyle={{
borderColor: '$conditional3',
borderWidth: 4,
marginHorizontal: '$md',
}}
/>
);
});
```
### Best Practices
- **Pagination:** Implement infinite scrolling by utilizing the `onEndReached` prop for large datasets.
- **Use Memoization:** Use [React.memo()](https://react.dev/reference/react/memo) to avoid unnecessary re-renders of list items.
- **Lazy Load Images:** If the list contains images, ensure they are lazy-loaded to avoid consuming memory unnecessarily.
- **Key Management:** Ensure `keyExtractor` returns a unique and stable key to avoid performance degradation caused by reordering or re-rendering items unnecessarily.
## Considerations
- **Internal State:** Internal state is not preserved when content scrolls out of the render window. Ensure all your data is captured in the item data or external stores like _Flux_, _Redux_, or _Relay_.
- **Prop Updates:** This is a `PureComponent` meaning it will not re-render if props remain shallow-equal. Make sure that everything your `renderItem` function depends on is in
passed as a prop (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on changes. This includes the `data` prop and parent component state.
- **Item Rendering:** To constrain memory and enable smooth scrolling, content is rendered asynchronously offscreen. This means it's possible to scroll faster than the fill
rate and momentarily see blank content. This is a tradeoff that can be adjusted to suit the needs of each application.
- **Key Management:** By default, the list looks for a `key` prop on each item and uses that for the React key. Alternatively, you can provide a custom `keyExtractor` prop.
### Accessibility Considerations
- **Focus Retention:** Retain focus and scroll position when adding or removing items from the list.
- **Content Labeling:** Ensure each list item has accessible labels or descriptions for screen readers.
### Performance Considerations
- **Windowing:** Adjust the `initialNumToRender` and `windowSize` props to strike a balance between performance and UX.
- **Cell Recycling:** Use `CellRendererComponent` to efficiently recycle rendered items, especially for very large datasets.
- **Avoid Expensive Re-renders:** Avoid triggering unnecessary re-renders by memoizing components or using `React.PureComponent`.
```jsx render
```
```jsx render
',
description:
'Object or array of objects defining the style of the VirtualizedList component with design tokens',
},
{
name: 'hitSlop',
type: 'Insets',
description:
'This defines how far a touch event can start away from the VirtualizedList',
},
{
name: 'contentContainerStyle',
type: 'Abyss.Style<"View">',
description:
'Object or array of objects defining the style of the content container within the VirtualizedList component with design tokens. These styles will be applied to the virtualized list content container which wraps all of the child views',
},
{
name: 'contentInset',
type: 'Insets',
description:
'The amount by which the virtualized list content is inset from the edges of the virtualized list',
},
{
name: 'endFillColor',
type: 'Abyss.Color',
description:
'The color of the background of the list when there are no items to display',
},
{
name: 'ListFooterComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListFooterComponent. Accepts an object or array of objects which defines the style of the ListFooterComponent within the FlatList component with design tokens',
},
{
name: 'ListHeaderComponentStyle',
type: 'Abyss.Style<"View">',
description:
'Styling for internal View for ListHeaderComponent. Accepts an object or array of objects which defines the style of the ListHeaderComponent within the FlatList component with design tokens',
},
]}
/>
```
---
id: design-checklist
title: Design Checklist
---
## Overview
Welcome to Abyss! If you’re just starting out designing with Abyss, you’re in the right place. Here’s a checklist of everything you need to get up and running. Abyss design kit is available in Figma through our enterprise account (Optum/UHG)
## Create Figma Account
## Using the Designer Toolkit
## Review Updates
---
id: design-kit
title: Design Kit
---
## Overview
## Designer Toolkit
## Guidance
## Accessibility
## Contact Us
---
id: code-connect
title: Code Connect
---
## Figma Code Connect for Mobile
Figma Code Connect is a Design-to-Code tool that aims to scaffold out the code required to implement a Figma Design.
**Note:** Code Connect is currently in alpha and availability for components is changing. We invite you to discuss any enhancements or limitations in our Github Discussion Topic.
**Note:** Components on the UHC or Global Figma with Code Connect enabled may only be for the V2 version of the component. See the list below for supported components.
## Instructions
This Demo Video contains an overview of how to use Abyss with Code Connect.
- Open the Figma file with the component you want to use and select the component. In dev mode, the Code Connect will be viewable in the side bar under "Recommended Code".
- The button "Explore component behavior" will allow you to see the component in a preview mode. You can change available props and variants from this panel.
_Due to Figma limitations, not all possible combinations will be available through here. Check Abyss documentation._
```jsx render
```
#### Slot limitations
At this time, code connect does not support slots. If you need to use a slot, you will need to manually add it to the code after copying it from Code Connect.
The reccomended code section does not show the actual slot element's code.
```jsx render
```
### Supported Components
```jsx render
```
---
id: abyss-admirals
title: Abyss Admirals
isHidden: true
---
## Who are Abyss Admirals?
An Abyss Admiral is a highly specialized role for a
software engineer who is a dedicated member of a product delivery team.
The most basic and essential function of an Admiral is to act as a bridge
between the core Abyss ecosystem and the product team leveraging the
framework.
Acting as representatives or ambassadors for their products, Admirals
enable the adoption of a{' '}
scalable, federated software development model by sharing
the Abyss community's best practices with their teams. As subject matter
experts for Abyss, Admirals are encouraged to guide and mentor their
engineering teams, empowering them to take advantage of the benefits of
working in a collaborative enterprise environment.
## Benefits for Product Stakeholders
It's very important for product stakeholders to understand that an Admiral's involvement in their new responsibilities will reduce their capacity for delivering sprint work as a standard individual contributor. However, by allocating enough time for the role, Admirals will enable engineering scrum teams to measurably improve both quality and delivery metrics. It's recommended to dedicate between **30% - 50%** of an Admiral's capacity for this role, but could be up to 100% depending on the size and scope of the project.
Product stakeholders will be able to capitalize on the efficiencies gained by leveraging the collective knowledge and shared solutions that are accessible through the broader Abyss community. The benefits of staffing a dedicated Admiral on your product include:
- **Accelerated Solution Development:**
When delivery teams are asked to identify and create solutions to common problems, they’ll need to do so in between developing new features which can result in delays. An Admiral assists their product teams at critical moments by eliminating these bottlenecks and offering proven solutions, which in turn increases the speed of delivery.
- **Minimized Duplication of Work:**
The Abyss team facilitates the creation of reusable digital assets such that, when the business makes a new request, an Admiral can utilize a similar solution that was built previously for another team rather than building a new one from scratch, greatly minimizing cost and time to value.
- **Consistent Product Quality:**
It’s reasonable to assume that most teams will not be evenly balanced when it comes to experience and skill levels, resulting in products being built with different techniques and standards. Admirals can ensure that the quality of development is both consistent and in accordance with the established standards of other products built with Abyss.
- **Expansive Specialist Network:**
When working with an Abyss Admiral, product stakeholders obtain access to a network of highly experienced and qualified specialists including software architects, lead engineers, UX designers, accessibility experts who are motivated to craft the best product experiences possible.
## Benefits for Engineering Managers
It's very important for engineering managers to understand that an Admiral's involvement in their new responsibilities will reduce their capacity for delivering sprint work as a standard individual contributor. However, by allocating enough time for the role, Admirals will enable engineering scrum teams to measurably improve both quality and delivery metrics. It's recommended to dedicate between **30% - 50%** of an Admiral's capacity for this role, but could be up to 100% depending on the size and scope of the project.
Engineering managers will be able to capitalize on the efficiencies gained by leveraging the collective knowledge and shared solutions that are accessible through the broader Abyss community. The benefits of staffing a dedicated Admiral on your delivery team include:
- **Reduced Software Fragmentation:**
When individual teams are developing within disconnected, siloed environments, they’ll often discover multiple different approaches to solve the same problem. Admirals can act as advisors to prevent this additional overhead from occuring by raising awareness of pre-existing solutions.
- **Promote Engineering Growth:**
For an engineer who is eager to progress further along their career path, the Admirals program offers an elevated set of responsibilities for overseeing software projects. Since this role is both highly technical and relationship-oriented, coupled with a sense of personal accountability, Admirals can leverage this experience to explore their interest in management or technology leadership roles.
- **Accountability for Essential Tasks:**
Engineering teams are often overburdened with upkeep and maintenance related chores because they are given a lower priority than feature work. By assigning an Admiral to each project, engineering managers can verify that code quality, versioning, and peer review processes are being observed.
- **Optimized Outcomes:**
Admirals reduce the time and cost of development through specialization and economies of scale. By tapping into a centralized community of knowledge, skills, and experience, the Admirals program is able to streamline access to those scarce capabilities while also facilitating balanced, cohesive engineering teams.
## Admiral Assignments
- **Upgrade Abyss Versions:**
It's highly beneficial to keep your product up-to-date with the newest versions of Abyss. Inform your engineering team and product stakeholders of any new components, tools, or patterns your application can leverage.
- **Review the [release notes](/mobile/releases/) after a release** to determine the level of effort for upgrading to the latest version.
- **Run the command "npm run abyss"** to automatically upgrade all Abyss packages in your project.
- **Support for new features and defects** will only be included in new versions.
- **Monitor Code Quality:**
As an Admiral, the accountability of maintaining high standards for code quality starts with you. Become well-versed in JavaScript, React, ESLint, and SonarQube anti-patterns and shepherd your team away from these pitfalls, reducing the burden of unrestrained technical debt and extending the lifespan of your codebase.
- **Remediate runtime errors & warnings** observed in the browser's developer console for your product.
- **Inspect problems reported by [ESLint](https://eslint.org/docs/latest/rules)** and discuss rule modifications with other Admirals.
- **Triage issues identified by [Sonar](https://sonar.optum.com)** to ensure your product meets code quality benchmarks.
- **Manage Pull Requests:**
Within the GitHub repository for your product, you should encourage your team to open pull requests regularly. By consulting with other Admirals, you are in the most well-suited position to act as a code reviewer for your team.
- **Open draft PR's early** in the sprint to give you and your team enough time to review and offer feedback on the approach.
- **Offer comments and conduct reviews** for each PR before approving.
- **Merge PR's in a timely manner** to improve time-to-build metrics for your product.
- **Leverage Assets:**
Admirals should strive to identify all of the usuable assets that exist within Abyss, as well as the network of individuals involved. Becoming familiar with the abstract concepts of a framework will elevate the engineering maturity of your team.
- **Research code developed for Abyss** to understand the patterns for consistent, repeatable software practices.
- **Review and update documentation** which demonstrates guidance for best practices, guidelines, and considerations.
- **Foster relationships with key experts** who possess very specific and unique skillsets who can influence the growth of your product.
- **Continous Learning:**
To be successful, Admirals should provide thought leadership, direction, and appropriate recommendations for their teams and the Admiral community. The ability to both absorb and transfer knowledge is essential.
- **Have a self-starter attitude** and a passion for growing your career by being surrounded by like-minded engineers.
- **Seek opportunities for learning** by reading developer blogs, attending tech conferences, and networking with other Admirals.
- **Familiarize yourself with industry trends** by researching and recommending techniques for application development.
- **Sustainable Software:**
When left unchecked, the sustainability of an application can continously deteoriate. Admirals are able to counteract this by taking appropriate measures to establish a healthy development environment and extend the lifespan of a product.
- **Maintain a log of tech debt** and track the ongoing scope of maintainance tasks incurred from past sprints.
- **Conduct frequent pair programming** sessions with your team to guide current feature development.
- **Discuss upcoming requirements** with architects to establish a clear path for future stories in your product pipeline.
- **Abyss Contributions:**
With the Admiral contribution process, the development process for new assets can be accelerated by building the solution yourself as the need arises; rather than waiting for your idea to reach the top of the Abyss core backlog.
- **Determine the priority** for framework enhancements based on your product delivery schedule.
- **Discuss new ideas in [Office Hours](#abyss-office-hours)** with the core team and other Admirals.
- **Follow the [Contribution Workflow](#contribution-workflow)** shown below to share your proposals with the framework.
## Admiral Developers Guide
If an existing Abyss component doesn't meet your product's requirements, you can follow this guide for building and testing changes within your application's codebase. Start by cloning the package structure of abyss within your product, such as **'src/abyss/mobile/ui/Badge'** demonstrated below. If you are creating a new component, you can start with a similar one as a template, otherwise cloning the existing component is the recommended approach.
```txt
└── packages
└── mobile
├── node_modules
├── src
| └── ui
| └── Badge
| ├── index.js
| └── Badge.jsx
└── package.json
```
Next, replace the relative imports with absolute paths to **@uhg-abyss/mobile**. You can use any combination of Abyss package imports, open source libraries, and custom JavaScript dependencies to build your component.
```jsx
import React from 'react';
import PropTypes from 'prop-types';
import { styled } from '../../tools/styled';
import { useAbyssProps } from '../../hooks/useAbyssProps';
```
Replace with:
```jsx
import React from 'react';
import PropTypes from 'prop-types';
import { styled } from '@uhg-abyss/mobile/tools/styled';
import { useAbyssProps } from '@uhg-abyss/mobile/hooks/useAbyssProps';
```
Finally, to test your component changes, modify your import path by changing **'@uhg-abyss/mobile/ui/Badge'** to **'@src/abyss/mobile/ui/Badge'** which will use your local Abyss component. Once you have fully verified your changes, you can submit a new Pull Request back to [Abyss](https://github.com/uhc-tech/abyss/pulls) and showcase your updates in the Abyss office hours. Once merged, your contributions will be available in the next release!
## Contribution Workflow
As an Abyss Admiral the workflow for a contribution goes as follows:
1. Office Hours: Discuss proposal for new components, designs, architecture, and tools with other Admirals.
2. Abyss Contact us: If idea can be re-used, submit a new request with Abyss "Contact Us" form.
3. Develop Locally: Follow the steps in Admiral developers guide to create re-usable asset locally in your product.
4. Abyss GitHub: Before opening a new Pull Request, ensure that all requirements are met for UX, branding, and accessibility guidelines.
5. Abyss Office Hours: Demo proposed feature with Abyss core team and other Admirals.
6. Abyss Github: Pull Request undergoes modifications from feedback, acceptance, quality checks and merge.
The contribution will end with the finalized abyss packages

## Abyss Office Hours
| Day | Time | Meeting |
| --------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tuesdays | 3:00 - 4:00 PM **CST** | [Join Teams Meeting](https://teams.microsoft.com/l/meetup-join/19%3ameeting_YjVlMDM3OTgtY2ExYi00OTU0LWIyYTYtODk0NGUwN2E2MmUz%40thread.v2/0?context=%7b%22Tid%22%3a%22db05faca-c82a-4b9d-b9c5-0f64b6755421%22%2c%22Oid%22%3a%226e73a16f-0cf1-4fd2-9501-31c2c9038e9b%22%7d) |
| Thursdays | 9:00 - 10:00 AM **CST** | [Join Teams Meeting](https://teams.microsoft.com/l/meetup-join/19%3ameeting_YjVlMDM3OTgtY2ExYi00OTU0LWIyYTYtODk0NGUwN2E2MmUz%40thread.v2/0?context=%7b%22Tid%22%3a%22db05faca-c82a-4b9d-b9c5-0f64b6755421%22%2c%22Oid%22%3a%226e73a16f-0cf1-4fd2-9501-31c2c9038e9b%22%7d) |
---
id: abyss-contributors
title: Abyss Contributors
---
## Overview
First of all, thank you for your interest in contributing to Abyss. All of your contributions are valuable to the project! There are several ways you can get involved in the Abyss community and become a contributor:
- **Share Abyss:** Share the link to [Abyss](https://abyss.uhc.com) with members of your product team, and we'd be happy to discuss how we can help support your application.
- **Improve documentation:** Help us improve the Abyss Docs by fixing incomplete or missing sections, examples, and explanations.
- **Provide feedback:** The team at Abyss are constantly working to make the project better, please let us know what features you would like to see with the [Contact Us](/mobile/contact-us/) form.
## Abyss Code Repo
```jsx render
() => {
const packages = [
'api',
'core',
'desktop',
'ext',
'infra',
'mobile',
'parcels',
'utility',
'web',
];
const products = ['assets', 'docs', 'ext', 'scaffold', 'storybook'];
return (
{' '}
The Abyss source code monorepo contains both core packages and products
Packages:
{packages.map((item) => {
return (
{item}
);
})}
Products:
{products.map((item) => {
return (
{item}
);
})}
{``}
}
>
Visit
);
};
```
### Setting Up Project Locally
For the essential system tools to get Abyss running on your local development environment, visit our [workspace setup](/mobile/developers/workspace-setup) guide.
To set up, clone the abyss repository:
```bash
# Make the abyss-projects directory
mkdir abyss-projects && cd abyss-projects
# Clone the abyss repository
git clone https://github.com/uhc-tech/abyss.git
```
Afterwards, install the dependencies for `abyss` on your machine:
```bash
# Go into the abyss directory
cd abyss
# Install abyss dependencies
npm i
```
Then you are ready to start `abyss-docs` on your machine:
```bash
npm run docs
```
### Commit Conventions
Head to the Abyss source code for updates and additions to our Abyss NPM packages and documentation. With several contributors working in these repos daily, it's important to write your commit messages to be as descriptive as possible.
Commit Convention:
```
[area] Optional title: Message
```
Examples:
```
[docs] Button: Edit accessibility section
[@uhg-abyss/ui] useLoadingOverlay: Add remove handler
[@uhg-abyss/core] Fix non-prod deployment scripts
[@uhg-abyss/ui] Carousel: New feature added
[docs] Doc scripts: Fix docs deployment script
```
### Git Branch Names
Naming the branch you're working on helps repository maintainers understand the changes being made when the PR is opened. Using consistent branch name prefixes also allows build tools to automatically categorize the branches using labels. Branch names should be all lowercase (with the exception of US and DE) and include hyphens between words. All branches are divided into four groups:
- **story/#######** - Changes associated with a User Story, use the unique 7-digit number from Rally followed by a task description.
- **defect/#######** - Changes associated with a Defect, use the unique 7-digit number from Rally followed by a task description.
- **refactor/** - Changes to the repo that aren't documented in Rally are considered refactors, so use the task portion to add detail to your branch name.
- **release/** - Used specifically by build tools, this branch name is exclusive to release notes and documentation leading up to a new release.
Examples:
```
git checkout -b story/US2434515-developer-toolkit
git checkout -b defect/DE308703-button-accessibility
git checkout -b refactor/select-list-multi-docs
git checkout -b story/US1533842-use-loading-overlay
```
Branch Name Rules:
- Branch prefix must start with **story**, **defect**, **refactor**, or **release**
- Branch name must be only **lowercase letters, numbers, and hypens**
- **US###** and **DE###** are valid character exceptions
## Secure Groups
Visit secure.uhc.com to request permissions groups:
- **abyss_contributors**: For write access to abyss code repositories
## Developer Tools
Abyss is built using a list of trusted resources. Below are links to what makes up the framework of Abyss Mobile.
```jsx render
() => {
const devLinks = [
{
id: 1,
name: 'React Native',
href: 'https://reactnative.dev/',
},
{
id: 2,
name: 'Emotion',
href: 'https://emotion.sh/docs/introduction',
},
{
id: 3,
name: 'React Navigation',
href: 'https://reactnavigation.org/docs/getting-started',
},
{
id: 4,
name: 'npm ',
href: 'https://docs.npmjs.com/about-npm',
},
];
return (
{devLinks.map((link) => {
return (
}
>
{link.name}
);
})}
);
};
```
If you're ready to get started with Abyss on your own, checkout the Abyss StarterKit (coming soon) to get started.
## Design Tools
Abyss has a dedicated team of designers creating a Design Kit on Figma. Below are some resources to help developers navigate these tools:
```jsx render
() => {
const designLinks = [
{
id: 1,
name: 'Abyss Design Kit',
href: 'https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=1180-3541&t=1l9yUfKeafljt2k0-0',
},
{
id: 2,
name: 'Figma for developers',
href: 'https://www.figma.com/best-practices/tips-on-developer-handoff/an-overview-of-figma-for-developers/',
},
{
id: 3,
name: 'UHC branding',
href: 'https://brand.uhc.com/design-with-care',
},
{
id: 4,
name: 'Optum branding',
href: 'https://brand.optum.com/',
},
];
return (
{designLinks.map((link) => {
return (
}
>
{link.name}
);
})}
);
};
```
If you're a designer and want to dive deeper into the Abyss Design Kit, visit our Designer Getting Started (coming soon) page to learn more.
---
id: documentation-guide
title: Documentation Guide
---
## Overview
The documentation pages are organized under the **docs** directory shown below. When adding a new component, tool, or guide to Abyss Docs, create a new markdown.md file under the associated folder.
```txt
abyss-docs-web
└── docs
└── mobile
├── brand
├── developers
├── hooks
├── tools
└── ui
```
## Markdown Structure
Each markdown file should begin with the following metadata, as an example:
```md
---
id: card
category: Layout
title: Card
description: A single or multi-section container used to display content related to a single subject.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/Sk3MrHYxjT39TKDzDU5LBc/Abyss-Mobile?node-id=12334%3A61355
---
```
Every doc page is divided into three tabs: Overview, Integration and Accessibility. Within the body of the markdown file, use these tabs to group sections of information.
```
**Overview Content**
**Integration Content**
**Accesibility Content**
```
## Overview Tab
###### Import statement
Add the import statement for the feature like such:
```jsx
import { Alert } from '@uhg-abyss/mobile';
```
###### Component Sandbox
Add Sandbox after the import statement for any components that make sense
to have a sandbox. Inputs are controlled props that can be adjusted by the user using the Sandbox features. Each input contains `prop`, `type` and optionally: `options` and, `defaultValue`.
To create a Sandbox, use the convention below:
```jsx sandbox
{
component: 'Alert',
inputs: [
{
prop: 'title',
type: 'string',
},
{
prop: 'description',
type: 'string'
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'info', value: 'info' },
]
},
]
}
Go To Results
```
###### Property examples
Following the Sandbox, it's important to show the ability of each property separate of the others. We break each one down, giving it a title, description and jsx example showing variants of that specific property. For example, if you wanted to show the sizes for Button, you'd write:
```
```
Since there are multiple visual variants of Button, which use the same sizing convention (`small` & `large`) we can combine the visuals under the one size example by organizing them utilizing the built-in Layout component from the Abyss library. Here's what the combined example looks like:
```
```
To follow the complexity of each prop example, use the following rules to properly document the feature:
- **When organizing the list of examples,** they should be ordered from simple to complex starting with size or width
- **Start each example case** with "Use the `prop-name` property to..." followed by an explanation
- **For props with a pre-set list of variants,** add a sentence listing out the variant options "Variants include `variant-1`, `variant-2`", and so on
- **For props with a default value,** add "The default value is set to `value`"
- **For the customization example section,** include the sentence “If further customization is needed, most styles of `component-name` can be overridden by passing style props to `abyss-component-name`. See the class table on each component for more details”
- **Size and width examples** should include the list of Abyss style sizes
- **Examples may include:** size, width, isDisabled, controlled, uncontrolled, loading, and customization. Take a look at other doc pages for examples of how to best format the component you're documenting
## Integration Tab
Implementing a props table and classes table for the component, and any sub-components gives users an in-depth view of the component without having to visit the code. (The below example is modified for this template. Please refer to the Button component for a full list of props and classes).
Follow these rules when creating a Props Table:
- **Prop name** is lowercase
- **Type** is one of the following: boolean, function, array, shape, number, string, number | string
- **Description** first word is uppercase, followed by a brief description of the props use
Follow these rules when creating a Classes Table:
- **Class name** is lowercase and uses dashes to separate words
- **Description** first word is uppercase, followed by a brief description of the class
#### Example of Integration Tab
```jsx render
```
```jsx render
```
## Accessibility Tab
This tab is important to be as thorough and in-detail as possible, adhering to the WAI-ARIA design guidelines. Check out the accessibility documentation on React Native for guidence during development.
Follow this pattern when creating the Accessibility tab:
- **Brief description** write a description about the component, and link to the WAI-ARIA website page referring to the component
- **Sandbox** allows our A11Y partners to practice assistive technology on the component in a dedicated field
- **Keyboard interactions table** referring to the WAI-ARIA keyboard interactions, create a table with all interactions usable for the specific component
- **Additional guidance** note any additional guidance features of the component, including (but not limited to) Decorative Icons, Loading State, etc.
#### Example of Accessibility Tab
An alert is an element that displays a brief, important message in a way that attracts the user's attention without interrupting the user's task. Dynamically rendered alerts are automatically announced by most screen readers, and in some operating systems, they may trigger an alert sound. It is important to note that, at this time, screen readers do not inform users of alerts that are present on the page before page load completes.
Adheres to the Alert WAI-ARIA design pattern.
```jsx live
{}}
/>
{}}
/>
{}}
/>
{}}
/>
```
```jsx render
```
###### Decorative Icons
In the alert below, since the word “Warning” appears next to the icon, the icon is considered decorative and must be ignored by assistive technology. The icon does not need to meet the 3:1 minimum contrast requirement against its adjacent color.
```jsx live
```
###### Close Button Guidance
Keyboard operation: if the “close” button is used on the alert, it must be keyboard accessible. A keyboard only user must be able to tab to the button, and activate it with the space bar and the enter key.
```jsx live
{}}
/>
```
Note: per the WAI ARIA specification, when the “alert” role is used, the user should not be required to close the alert. In this case, it is assumed that the close button is provided as a convenience and the user is not explicitly required to close the alert.
---
id: mobile-contribution-standards
title: Mobile Contribution Standards
---
## Overview
Thanks for getting involved with Abyss! If you've made it here we'll assume you've reviewed the [Abyss Contributors](/mobile/developers/contributors/abyss-contributors) page. To make the contribution process go as smooth as possible, we've laid out our code standards and development steps for you below.
As a reminder the component you are developing should _already_ be approved by product, design, and accessibility.
## Code Standards
While components may differ, most Abyss Mobile UI components have the following...
The outermost styled element will be named `ComponentNameRoot`. The rest of the names should describe what they contain. Below is a simplified example from [Modal](/mobile/ui/modal/)
```
// code
```
The `useAbyssProps` hook must be imported in each component. This allows consuming teams to customize the style of the component and gives the ability to assign unique test-ids.
```
const abyssProps = useAbyssProps(props);
```
`abyssProps` are spread into each element that will allow for customization and testing. The class names start with the component name followed by a dash and then the element name. These names should be simple and self-explanatory. For example, `button-root` describes the root element and `button-label` describes the label element.
```
```
Add accessibility props when applicable.
```
```
Don't forget the display name.
```
Button.displayName = '@uhg-abyss/mobile/ui/Button';
```
### Types, Props, and Classes
All the types, props, and classes used in the component must be defined in a `ComponentName.types.ts` file. This file should export a TypeScript interface for the component's props, classes, and any reused types.
Below is a simplified example of Button:
```
export type ButtonClasses = {
'button-root': Abyss.Class<'Animated.Pressable'>;
'button-label': Abyss.Class<'Animated.Text'>;
};
```
Unless a prop is marked as required in the TypeScript interface, be sure to add a default value where applicable (and within the component itself).
```
export interface ButtonProps
extends Abyss.BaseProps {
/**
* The contents of the button component
*/
children?:
| React.ReactNode
| ((state: PressableStateCallbackType) => React.ReactNode);
/**
* Defines the button type (style)
* @default 'filled'
*/
type?: 'filled' | 'outline' | 'text';
/**
* Defines the button size
* @default 'large'
*/
size?: 'large' | 'small';
/**
* Disables the button
* @default false
*/
isDisabled?: boolean;
/**
* Callback fired when the Button is pressed
*/
onPress?: Abyss.GestureResponderEventHandler;
}
```
```
export interface ButtonRef extends Abyss.PressableRef {}
```
Once the `ComponentName.types.ts` file is complete import the necessary elements into the `ComponentName.tsx` file.
```
import type { ButtonProps, ButtonRef } from './Button.types';
```
The full props spread may look something like the example below.
`ButtonRoot` is the outermost `Pressable` component, so `size` and `type` are passed in for styling, as well as all the props pertaining to press interactions: `onPress`, `onPressIn`, `onPressOut`, and `disabled`. `{...abyssProps('button-root')}` is added, and for the Button component specifically, accessibility props are only within the `ButtonRoot` element.
```
```
## Development Workflow
###### 1. Developer Refinement
Before starting development, you are **required** to attend our Mobile Developer refinement session. Here we will discuss the development plan for the component you are contributing. This includes outlining code already available to be used within your component, as well as what we expect to be reusable from your component.
###### 2. Development
Please review our [Code Standards](/mobile/developers/contributors/mobile-contribution-standards/#code-standards) before you get started, and remember we're here to help! Feel free to reach out an Abyss Mobile developer and attend [office hours](/mobile/contact-us/?card=meetings) for anything that comes up during development.
###### 3. Documentation
A component is not complete without proper documentation. Please see our [Documentation Guide](/mobile/developers/contributors/documentation-guide/) for more details and examples. Be sure to continue to update documentation with any changes from the Peer, QE, and A11y reviews.
###### 4. Peer Review
After you've completed development, make a pull request and reach out to the Abyss Mobile developer that has been assigned to review your component. They will do an initial review, as well as check any code changes after QE and Accessibility testing. Any changes requested bring you back to [development](/mobile/developers/contributors/mobile-contribution-standards/#2-development).
###### 5. Quality Engineering Review
Once the PR is complete, your component will be sent to our quality engineer for testing. Any changes requested bring you back to [development](/mobile/developers/contributors/mobile-contribution-standards/#2-development).
###### 6. Accessibility Review
After your component has been approved by QE, it will be passed on to our accessibility engineer for testing. You are responsible for adding accessibility elements within your component. Check out our [Accessibility Testing](/mobile/developers/testing/accessibility-testing/) page and the React Native documentation for further guidance. Any changes requested bring you back to [development](/mobile/developers/contributors/mobile-contribution-standards/#2-development). If the changes made only pertain to accessibility, the component does not need to be reviewed again by QE.
## Definition of Done
By contributing to Abyss, you are committing to the full development cycle. A component is complete when all changes have been made and accepted by the Peer, QE, and Accessibility reviews, and is thoroughly documented.
---
id: ai-code-gen-how-to
title: How to use AI to perform code generation "CodeGen" with Abyss
sidebar_label: AI Code Generation
searchSiteWide: true
---
## Design-to-Code
## Prompt-to-Code
---
id: installation
title: Installation
---
There are two ways to go about installing Abyss - either by creating a new Abyss app or by adding Abyss to an existing application.
## Create Abyss App (Recommended)
The recommended way to get started with Abyss is by using `create-abyss-app`.
Go to our [tutorials](/mobile/developers/tutorials/create-abyss-app/) to get started!
### Advantages
- **Zero Configuration Setup**
- All tools are already configured that are essential for React development. Tools like Webpack (for bundling your code) and Babel (for using modern JavaScript features).
- **Easy To Use**
- You can start developing and see those results immediately.
- **Optimized Build Output**
- Provides optimized production builds out of the box, including minification, concatenation, and efficient loading (e.g., code splitting).
- **Community and Support:**
- Many team are already using the `create-abyss-app`, it offers significant support, regular updates, and a large number of resources for troubleshooting.
## Existing Application
For teams that want to use Abyss web within an existing React framework (i.e. NextJs) or are unable to migrate their existing application to a create-abyss-app you can still use Abyss within your application.
### Peer dependencies
Please note that react and react-native are peer dependencies, meaning you should ensure they are installed before installing Abyss.
```jsx
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-native": ">=0.63.0 <1",
"react-native-safe-area-context": ">=3.0.0",
"react-native-screens": ">=2.0.0",
"react-native-svg": ">=12.0.0"
"@react-navigation/bottom-tabs": ">=5.0.0",
"@react-navigation/native": ">=5.0.0",
"@react-navigation/native-stack": ">=5.0.0",
},
```
### Install Abyss Mobile
To add Abyss mobile to an existing application, first install the Abyss dependencies:
```jsx
npm install @uhg-abyss/mobile
```
Then, wrap your application root component with [`ThemeProvider`](/mobile/ui/theme-provider).
The `ThemeProvider` enables global theming for your application, with the option to customize or rely on the default styles of Abyss components. Utilizing React's context, it distributes your theme to all nested components.
```jsx
import { ThemeProvider } from '@uhg-abyss/mobile/ui/ThemeProvider';
const theme = createTheme('uhc');
function Demo() {
return (
);
}
```
## Upgrading Abyss
Abyss releases [New Versions](/mobile/releases/) on a biweekly basis. For further details, refer to our [Versioning Guide](/mobile/developers/migration/versioning-guide/).
Benefits to staying current with the latest version of Abyss include:
- **Adhering to Brand Guidelines**
- Align with the latest branding guidelines, ensuring your application maintains a consistent look and feel with the overall brand identity.
- **Enhanced Security**
- Address vulnerabilities and security enhancements to protect your application against emerging threats.
- **Improved Accessibility**
- As accessibility standards evolve, Abyss updates provide enhancements and fixes that help ensure your application is accessible to all users, including those with disabilities.
- **Access to New Components Features**
- Gain access to new components and features that can enrich the user experience and offer new functionality for your application.
- **Bug Fixes**
- Addresses defects that improve the stability and performance of your application.
- **Efficient Upgrades and Minimal Regression Testing**
- Staying updated with the latest version simplifies the upgrade process and minimizes related regression testing efforts.
### How To Upgrade Abyss
You can upgrade Abyss by running the following command in the root of your application:
```bash
npm install @uhg-abyss/mobile@latest
```
```bash
yarn add @uhg-abyss/mobile@latest
```
---
id: v2-prepping-guide
title: Prepping for V2
---
```jsx render
```
## Prepping for V2 of Abyss
This is a prepping guide for ways teams can prepare for the
upgrade from Abyss V1 to V2 before V2 is officially released.
**What is the difference between a prepping guide and a migration guide?**
This prepping guide is different from the migration guide that will be released with Abyss V2. Understanding these differences will help you plan your approach:
| Prepping Guide (Current) | Migration Guide (Future) |
| ----------------------------------------------- | ------------------------------------------------------------ |
| Available **before** V2 release | Will be available **after** V2 release |
| Focuses on **gradual preparation** | Provides comprehensive instructions for full migration to V2 |
| Helps distribute workload across sprints | Will be a one-time migration effort |
| Identifies components to start replacing now | |
| Allows teams to adopt V2 patterns incrementally | |
| **Reduces** migration complexity later | |
By following this prepping guide now, you'll significantly reduce the effort required
when the full migration guide is released with Abyss V2.
## Dependencies
```jsx
// from:
- "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
// to:
+ "react": "^18.0.0 || ^19.0.0"
```
## Components
With the migration to Abyss V2 we are making several changes to our components. This includes:
- **Prop changes**: Some props have been removed, modified, or renamed.
- **Class changes**: Some classes have been removed and renamed.
- **Component deprecations**: Some components will be deprecated and replaced with new ones.
- **Component breaking changes**: Some components will have breaking changes that may affect how they are used in your application.
### Deprecations
Here is a list of tools/hooks/components that will no longer be available in Abyss V2:
**Note:** This list is not exhaustive and may change as we finalize the migration.
Teams should start replacing these components with their new counterparts or alternative
solutions **now**, rather than waiting for the V2 release. By proactively doing this
now, you can:
- Reduce the refactoring effort required when V2 is officially released
- Migrate in smaller, more manageable increments
- Identify and resolve integration issues earlier
- Ensure a smoother and quicker transition to V2
### Component breaking changes
We've documented all component changes to help with migration planning. For details, see the [Component Changes](/mobile/developers/migration/v2/components/) section.
Many V2 components are already available with a "V2" prefix (e.g., `V2Button`). Start using these now to ease migration.
**Note:** When V2 is officially released, the "V2" prefix will be removed and these components will replace their V1 counterparts. For example, `V2Button` will become `Button`.
**Why should I use the V2 components now?**
- Familiarize yourself with the new APIs and features
- Identify any potential issues or changes in behavior early
- Ensure your codebase is ready for the V2 release without needing a complete overhaul
- Many of these components were completely rewritten to improve performance, accessibility, and usability
- These components have many added features and improvements that are not available in the V1 components (e.g., tokens, design improvements, etc.)
**Note:** These V2 components may change before the official V2 release. However, they are stable for production use and can be safely integrated into your application.
---
id: v1-to-v2-guide
title: V1 to V2 Guide
isHidden: true
---
```jsx render
```
---
id: components
title: Component Changes
---
```jsx render
```
## Overview
This guide focuses on breaking prop changes to be aware of when migrating from Abyss V1 to V2. These include:
- Props that have been removed
- Props whose behavior or typings have been updated
- Props whose names have been changed but whose functionality remains the same.
This guide does **not** cover:
- New props added in V2
- Class changes
- Token changes
- Additional features and enhancements
For complete documentation of all available props, including new features added, refer to each component's dedicated documentation page.
## Badge
## Banner
## Button
## Carousel
## CellGroup
### Cell
## DonutChart
## LoadingSpinner
## Popover
## Rating
## SelectInputMulti
## Skeleton
## Timeline
---
id: overview
title: Overview
---
Abyss is a full-stack mobile application framework that enables you to build products faster and easier than ever. It features a comprehensive set of tools that weaves together the best parts of React Native and GraphQL. By taking common patterns and modularizing them into accessible and reusable packages, Abyss is designed to accelerate the development of production-ready React Native applications.
The framework handles all heavy lifting behind the scenes, allowing you to focus on core business logic specific to your product. Automated code quality tools analyze, identify, and correct errors in the code, giving developers real-time feedback and training to standardize programming styles. With improvements in project maintainability, scalability, and source code quality, Abyss aims to deliver the best overall development experience.
Developers looking to use Abyss must have, or obtain access via Secure, to Artifactory (repo1.uhc.com)
## Learning React Native
Just starting your journey with React Native? Abyss is a framework built on top of the popular React Native library. To get started, visit the React Native documentation. If you are interested in learning high-level concepts, check out the getting started guide for React Native.
## Developer Tools
Abyss is built using a list of trusted resources. Below are links to what makes up the framework of Abyss Mobile.
```jsx render
() => {
const devLinks = [
{
id: 1,
name: 'React Native',
href: 'https://reactnative.dev/',
},
{
id: 2,
name: 'Emotion',
href: 'https://emotion.sh/docs/introduction',
},
{
id: 3,
name: 'React Navigation',
href: 'https://reactnavigation.org/docs/getting-started',
},
{
id: 4,
name: 'npm ',
href: 'https://docs.npmjs.com/about-npm',
},
];
return (
{devLinks.map((link) => {
return (
}
>
{link.name}
);
})}
);
};
```
## Support
If you're ready to get started with Abyss for your next project, check out our [Contact Us](/mobile/contact-us) page. Submit a new support request and let us know how we can help your team. If you found Abyss to be helpful, please give us a star on github!
---
id: style-customization
title: Style Customization
description: Guide to override styles for Abyss components.
design: https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/Abyss-Design-System?node-id=0%3A1
---
## Overview
Every Abyss component supports style customization using class names. Customization should be kept at a minimum, as the Abyss components are set to create a standard across all UHG affiliated products.
## Prop Overrides
To apply your styles to any component, go to the **Integration** tab under component documentation and find the classes table. The class name column will tell you how to target specific elements in any component.
### Button Example
Here you have a default `Button` component.
```jsx live
```
Similarly, to customize `Button` component, you can target specific class names to change the styles. The `Button` component should maintain a 3:1 color contrast ratio. Please visit the [accessibility](/accessibility) documentation page to read more on designing an accessible component.
```jsx render
```
```jsx
// Add styles to Button
```
```jsx live
```
## States
Components that allow for additional customization depending on their state can be configured by passing the desired style to the Abyss class using the `&:state` selector. Available states will be displayed on the integration tab.
```jsx live
() => {
const today = new Date();
const day = today.getDate();
const [value, setValue] = useState(today);
return (
{
return date.getDay() === 6;
}}
styles={{
'abyss-calendar-day-label': {
'&:selected': { color: '$primary1' },
'&:disabled': { color: '#99A8C9' },
},
'abyss-calendar-selection-circle': {
backgroundColor: '#d9f6fa',
},
}}
/>
);
};
```
---
id: quality-engineering
title: Quality Engineering
description: QE Testing Overview
---
## Dedication To Quality
## Test Plan
## Automation Testing
Automation testing of Abyss components is a top priority. Currently, our automation tests consist of the following:
### Web
### Mobile
### Unit Testing
## Manual Testing
## FAQ
---
id: end-user-spec
title: End User Specifications
description: Abyss Spec
---
## Version Requirements
## Testing and Review
## How are these numbers calculated?
## Abyss Web
## Abyss Mobile
\* Last updated March 2025. To ensure this document is kept up to date and relevant, it should be revisited and revised with the latest metrics information on a set schedule, such as quarterly or bi-annually.
---
id: component-testing
title: Component Testing
description: Guide on how to facilitate testing of Abyss Mobile components.
---
## testID
To facilitate the usage of component testing libraries such as **[React Native Testing Library](https://callstack.github.io/react-native-testing-library/docs/getting-started)** you have the option of adding a `testID` attribute to a component's corresponding elements. By passing `testID` in as a prop with a value of the desired string id this attribute will be appended to all component elements that include a unique Abyss class name. Please see the Integration tab and the Classes sub-heading for each component to determine which elements will receive this test id. The resulting `testID` value will be a concatenated string that combines the value passed in with the prop and the element's unique class name.
For example, the following code:
```jsx live
Add your dependents to your account to view their claims and coverage.
```
will render the following structure:
```jsx
Add your dependents to your account to view their claims and coverage.
May 13, 2025
```
## Change testing strategy
By default, the `testID` will have an abyss class name appended to it. If you do not want this, you can use the [`TestProvider`](/mobile/ui/TestProvider) component to change the testing strategy.
The `TestProvider` component has two strategies: `"class"` and `"root"`.
### Root strategy
The `"root"` strategy applies the `testID` only to the root element of the component. This means you won't be able to target nested elements within the Abyss component for testing.
For example, let's say the `testID` of [ProgressBar](/mobile/ui/ProgressBar) is set to `"your-test-ID"`.
```jsx
```
You can use the following code to find and test the element:
```jsx
import { render } from '@testing-library/react-native';
const screen = render(
);
const element = screen.getByTestId('your-test-ID');
```
### Class strategy
The `"class"` strategy (similar to default) allows testing of nested components by appending the Abyss class name to your `testID`. This creates unique identifiers for each element within the component.
For example, let's say the `testID` of [ProgressBar](/mobile/ui/ProgressBar) is set to `"your-test-ID"`.
```jsx
```
You will have to look at the classes for the ProgressBar component to determine which elements will receive this test ID
and have its class name appended to it.
```jsx render
```
The resulting test IDs will be _**`"your-test-ID-abyss-progress-bar-root"`**_ & _**`"your-test-ID-abyss-progress-bar-slide"`**_.
You can then use the following code to find and test an element's subcomponents:
```jsx
import { render } from '@testing-library/react-native';
const screen = render(
);
const element = screen.getByTestId('your-test-ID-abyss-progress-bar-slide');
```
---
id: accessibility-testing
title: Accessibility Testing
---
## Overview
Mobile accessibility, also known as A11Y, is the design and creation of mobile applications that can be used by everyone regardless of age, device, or disability. Accessibility support is necessary to allow assistive technology to interpret mobile pages. Abyss fully supports building accessible mobile applications and follows the Web Content Accessibility Guidelines (WCAG 2.1) and the UHG Accessibility Engineering Standards by the Accessibility Center of Excellence (ACOE).
The list below are steps to take as a developer to ensure accessibility compliance. Please take a minute to read through the following testing resources and familiarize yourself with how to utilize them for best practices.
## Keyboard Navigation
Use an external Bluetooth keyboard only to navigate the page without using your finger to tap or swipe. A visual indicator, known as the keyboard focus, should appear when navigating content. Look for difficulty reaching or activating interactive components, or if the focus becomes trapped on portions of the screen.
Expected keyboard behavior for custom components is typically the following, but there are exceptions
- Content navigation
- **Tab** to enter a component
- Use **arrow keys** to navigate within the component
- **Tab** to exit the component
- Interacting with CTA or form components
- **Enter** or **Space** to mimic a ‘tap’ or ‘press’
- **Arrow keys** to navigate to an item within a list OR mimic a ‘swipe’
- **Tab** to move onto the next item
## Desktop Development Tools
XCode's Accessibility Inspector tool is available for inspecting the code of the application for accessibility features and labels via a mobile emulator.
## Screen Reader Mobile Controls
A Screen Reader is an accessibility tool used primarily by sight-deficient users to navigate computer/mobile content. They interact with applications by reading aloud the content presented in the code. On mobile devices, users utilize either custom tap/swipe controls, Bluetooth keyboards, or both, to interact with the application. These users are impacted the most from lacking A11Y implementation.
Testing with a screen reader on physical mobile devices is important to understand if the code is working effectively for these tools.
Mobile devices provide the following screen readers, each with similar, yet unique functionality
- iOS VoiceOver: Learn about VoiceOver gestures
- Android TalkBack: Learn about TalkBack gestures
## NPM Packages
Most NPM packages rely on axe-core. Set an impact level and start with critical issues then work down. Remember to allow time to fix critical issues in the User Story. Otherwise, the product developers will get frustrated and learn to ignore the errors, which defeats the purpose and doesn't help anyone.
## Linting
For linting rules, work with an Accessibility Engineer to determine what to include there.
## Summary
Remember, the tools/processes mentioned above don't catch all A11Y issues, but they serve as a great start to empowering the team to do some of your own testing.
You can learn more from the Mobile Accessibility page in the Accessibility Knowledge Center.
For further information, reach out to an Accessibility Engineer!
## Accessibility Tools
If you're looking for an in-depth overview of what accessibility standards Abyss is working towards, visit our Abyss [Accessibility page](/web/accessibility).
```jsx render
() => {
const accessibilityLinks = [
{
id: 1,
name: 'WCAG 2.1',
href: 'https://www.w3.org/WAI/WCAG21/Understanding/',
},
{
id: 2,
name: 'Color Contrast Analyser (CCA)',
href: 'https://webaim.org/resources/contrastchecker/',
},
{
id: 3,
name: 'W3 Validator',
href: 'https://validator.w3.org/favelets.html',
},
{
id: 4,
name: 'Digital A11y',
href: 'https://www.digitala11y.com/accessibility-bookmarklets-testing/',
},
{
id: 5,
name: 'React Native Accessibility',
href: 'https://reactnative.dev/docs/accessibility',
},
];
return (
{accessibilityLinks.map((link) => {
return (
}
>
{link.name}
);
})}
);
};
```
---
id: create-abyss-app
title: Create Abyss App
---
---
**Note:** We would appreciate any feedback on our tutorial guide. If you are stuck at any time, make sure to contact the Abyss Admiral assigned to your team. If they cannot help, send a help request on our [Contact Page](/mobile/contact-us/).
---
Before starting, be sure to complete the [Workspace Setup](/mobile/developers/workspace-setup/) guide.
### Step 1: Create an App
Now, let's get started. Navigate to your terminal in order to create a new project named **"my-new-app"**. Once there, run the following command:
```bash
npx create-abyss-app my-new-app
```
### Step 2: Navigate to Project Directory
Next, navigate into the **my-new-app** project directory by running the command below:
```bash
cd my-new-app
```
### Step 3: Run Abyss
Finally, run the following command in order to get localhost running:
```bash
npm run mobile
```
Once you see the screen shown below, you are now up and running with Abyss!
```jsx render:phone
() => {
const Container = styled('ScrollView', {
height: '90%',
});
const theme = createTheme('uhc');
const links = [
{
title: 'About Us',
description: 'Learn more about the Abyss library',
url: 'https://abyss.uhc.com/web/about',
},
{
title: 'Components',
description: 'View the full list of components inside Abyss Mobile',
url: 'https://abyss.uhc.com/mobile/ui/button',
},
{
title: 'Tokens',
description: 'View our pallete of color tokens',
url: 'https://abyss.uhc.com/mobile/brand/uhc/colors/',
},
{
title: 'Custom Styling',
description: 'Learn how to customize Abyss components',
url: 'https://abyss.uhc.com/mobile/developers/style-customization',
},
{
title: 'Navigation',
description:
'Learn to handle moving between screens inside your application',
url: 'https://abyss.uhc.com/mobile/tools/create-bottom-tab-navigator',
},
{
title: 'Support',
description: 'Need help? Vsit our support page',
url: 'https://abyss.uhc.com/mobile/contact-us',
},
];
return (
Welcome to Abyss
Edit App.tsx to change
this screen and then come back to see your edits.
{links.map((link) => {
return (
window.open(link.url)}
/>
);
})}
);
};
```
Great job, you have successfully created an abyss app!
---
id: import-components
title: Import Components
---
---
**Note:** We would appreciate any feedback on our tutorial guide. If you are stuck at any time, make sure to contact the Abyss Admiral assigned to your team. If they cannot help, send a help request on our [Contact Page](/mobile/contact-us/).
---
### Step 1: Open App.tsx
In Visual Studio Code, open **my-new-app** project. From here, navigate into **products/mobile**, and open the **App.tsx** file.
```txt
└── products
└── mobile
└── App.tsx
```
### Step 2: Import React
Anytime you’re using a react component, make sure to import the following dependency at the top:
```jsx
import React from 'react';
```
### Step 3: Importing Component
Depending on the project requirements, the **@uhg-abyss/mobile/ui**, **@uhg-abyss/mobile/hooks**, and **@uhg-abyss/mobile/tools** libraries have different components in order to assemble products quickly.
There are three ways to import resources: Directly from one of the libraries above, from **@uhg-abyss/mobile**, or from the file for that resource
**@uhg-abyss/mobile/ui/ComponentName**
Let's start with the **Card** component. A Card acts as a container used to display content related to a single subject.
You can access the documentation for the [Card](/mobile/ui/card/) through the Abyss Portal. The import statement for a card can be any of the following:
```jsx
import { Card } from '@uhg-abyss/mobile';
```
```jsx
import { Card } from '@uhg-abyss/mobile/ui';
```
```jsx
import { Card } from '@uhg-abyss/mobile/ui/Card';
```
In **App.tsx**, within the tsx of **App** functional component, insert the following code:
```jsx
Hello tutorialWe did it!
```
### Step 4: Verifying Your Code
Your code in **App.tsx** should now look similar to this:
```jsx
import React from 'react';
import { Image, SafeAreaView, ScrollView, View } from 'react-native';
import {
createTheme,
ThemeProvider,
Layout,
Text,
Card,
Heading,
} from '@uhg-abyss/mobile';
const theme = createTheme('uhc');
function App(): React.JSX.Element {
return (
Welcome to Abyss
Edit App.tsx to
change this screen and then come back to see your edits.
Hello tutorialWe did it!
);
}
export default App;
```
```jsx render
const App = () => {
const theme = createTheme('uhc');
return (
Welcome to Abyss
Edit App.tsx to
change this screen and then come back to see your edits.
Hello tutorial
We did it!
);
};
render(() => {
return ;
});
```
Great job, you have successfully imported components!
---
id: screen-navigation
title: Screen Navigation
---
---
**Note:** We would appreciate any feedback on our tutorial guide. If you are stuck at any time, make sure to contact the Abyss Admiral assigned to your team. If they cannot help, send a help request on our [Contact Page](/mobile/contact-us/).
---
Before starting, be sure to complete the [Create Abyss App](/mobile/developers/tutorials/create-abyss-app/) tutorial.
## Step 1: Create New Files
In Visual Studio Code, open **my-new-app** project.
From here, navigate into **products/mobile/src/navigation**, and create a new file, named **"MyPlanNavigator.tsx"**.
Then, navigate to **products/mobile/src/screens**, and create a new folder named **MyPlan**. Within this folder, we'll be creating 3 files:
**"MyPlanScreen.tsx"**, **"CoverageScreen.tsx"**, and **"index.ts"**.
Your folder structure should look like this:
```txt
└── products
└── mobile
├── src
| ├── navigation
| | ├── HomeNavigator.tsx
| | ├── MenuNavigator.tsx
| | └── MyPlanNavigator.tsx
| ├── screens
| | ├── Home
| | ├── Menu
| | ├── MyPlan
| | | ├── CoverageScreen.tsx
| | | ├── index.ts
| | | └── MyPlanScreen.tsx
└── App.tsx
└── package.json
```
## Step 2: Create MyPlan Screen
Lets create a screen! We'll add a Plan Coverage card.
In **"MyPlanScreen.tsx"**, insert the following code:
```jsx
import React from 'react';
import { View } from 'react-native';
import { Card, CellGroup, Heading, IconBrand } from '@uhg-abyss/mobile';
export const MyPlanScreen = ({ navigation, route }) => {
return (
Plan Coverage
}
title="Coverage & Benefits"
onPress={() =>
navigation.navigate('Coverage', {
benefits: ['Medical', 'Dental', 'Transportation'],
})
}
/>
);
};
```
Then in **index.ts** , insert the following export command:
```jsx
// Exporting MyPlanScreen allows us to import and use MyPlanScreen in the Navigator
export { MyPlanScreen } from './MyPlanScreen';
```
In the code above, we have a Cell that navigates to another screen called **Coverage**.
The Coverage screen takes an array of benefits as a parameter.
Let's create that screen.
## Step 3: Create Coverage Screen
```jsx
import React from 'react';
import { View } from 'react-native';
import { Card, CellGroup, Heading } from '@uhg-abyss/mobile';
export const CoverageScreen = ({ navigation, route }) => {
// The benefits array from MyPlanScreen
const { benefits } = route.params;
return (
Coverage & Benefits
{benefits.map((benfit) => {
return (
{}} />
);
})}
);
};
```
```jsx
// Exporting MyPlanScreen allows us to import and use MyPlanScreen in the Navigator
export { MyPlanScreen } from './MyPlanScreen';
```
Then in **index.ts** , add the screen to the list of exports:
```jsx
export { CoverageScreen } from './CoverageScreen';
export { MyPlanScreen } from './MyPlanScreen';
```
## Step 4: Create a Stack Navigator
Next, we will create the stack navigator. In **MyPlanNavigator.tsx**, insert the following code:
```jsx
import React from 'react';
import { Pressable } from 'react-native';
import { createStackNavigator, IconSymbol } from '@uhg-abyss/mobile';
import { MyPlanScreen, CoverageScreen } from '@/screens/MyPlan';
const MyPlanStack = createStackNavigator();
export const MyPlanNavigator = () => {
return (
(
),
}}
/>
);
};
```
## Step 5: Add MyPlan Tab
Next, we will add the MyPlan Stack Navigator, to the main tab bar.
Navigate into **products/mobile/App.tsx**. There should already be two existing `Tab.Screen` components, representing the Home and Menu tabs.
Let's place a new `Tab.Screen` in between the existing tabs so that the My Plan tab shows 2nd on the tab bar.
First import the `MyPlanNavigator`.
```jsx
import { MyPlanNavigator } from '@/navigation/MyPlanNavigator';
```
Then add the MyPlan tab
```jsx
...
(
),
}}
name="HomeTab"
component={HomeNavigator}
/>
(
),
}}
name="MyPlanTab"
component={MyPlanNavigator}
/>
(
),
}}
name="MenuTab"
component={MenuNavigator}
/>
...
```
## Step 6: Create Navigation Types
Navigate to **products/mobile/src/navigation** and open **"navigation.ts"**.
Let's create a new `type` to represent the two screens' parameters. The `MyPlan` screen has no parameters and the `Coverage`
screen has a benefits array of strings.
In **"navigation.ts"**, insert the following code.
```ts
type MyPlanTabParamList = {
MyPlan: undefined;
Coverage: { benefits: string[] };
};
```
Now, we can create a `type` for the navigation and route props of each screen.
In **"navigation.ts"**, insert the the following code.
```ts
export type MyPlanTabScreenProps =
CompositeScreenProps<
BottomTabScreenProps,
RootStackScreenProps
>;
```
Next, let's navigate back to **"MyPlanScreen.tsx"** and add the `MyPlanTabScreenProps` type in the function's parameter.
```jsx
import { MyPlanTabScreenProps } from '@/types/navigation';
export const MyPlanScreen = ({
navigation,
route,
}: MyPlanTabScreenProps<'MyPlan'>) => {
// rest of the code
};
```
We can do the same thing in **"Coverage.tsx"**.
```jsx
import { MyPlanTabScreenProps } from '@/types/navigation';
export const CoverageScreen = ({
navigation,
route,
}: MyPlanTabScreenProps<'Coverage'>) => {
// rest of the code
};
```
Great job, you have successfully completed page routing!
---
id: custom-themes
title: Custom Themes
---
---
**Note:** We would appreciate any feedback on our tutorial guide. If you are stuck at any time, make sure to contact the Abyss Admiral assigned to your team. If they cannot help, send a help request on our [Contact Page](/mobile/contact-us/).
---
### Step 1: Create a Theme screen
In Visual Studio Code, open the **my-new-app** project. From here, navigate to **products/mobile/src/screens** and create a new folder named `ThemeScreen`. Within this new folder, create two new files named `index.ts` and `ThemeScreen.tsx`.
```txt
products
└── mobile
└── src
└── screens
└── ThemeScreen
├── index.ts
└── ThemeScreen.tsx
```
### Step 2: Choosing A Theme
In **ThemeScreen.tsx**, we are building our theme using the pre-defined `UHC` theme. You can choose between the different brands shown below:
Abyss offers several pre-defined themes: `UHC`, `UHG`, and `Optum`. You can find these themes [here](https://github.com/uhc-tech/abyss/tree/main/packages/abyss-mobile/src/tools/theme/variants).
While building **ThemeScreen.tsx**, you can choose any of the brands demonstrated below.
---
[UHC Theme](https://github.com/uhc-tech/abyss/blob/main/packages/abyss-mobile/src/tools/theme/variants/uhc.js)
```jsx
const theme = createTheme('uhc');
```
[UHG Theme](https://github.com/uhc-tech/abyss/blob/main/packages/abyss-mobile/src/tools/theme/variants/uhg.js)
```jsx
const theme = createTheme('uhg');
```
[Optum Theme](https://github.com/uhc-tech/abyss/blob/main/packages/abyss-mobile/src/tools/theme/variants/optum.js)
```jsx
const theme = createTheme('optum');
```
### Step 3: Customizing your Theme
There are multiple ways to customize and style your application. In this guide, we will focus on color and font customization.
To customize your brand's default themes to align with your product's branding, you can include a configuration object to add or override variables within the theme by adding values inside the **createTheme** function as shown below.
You can learn more about the **createTheme** function [here](/mobile/tools/create-theme).
```jsx
const theme = createTheme('uhc', {
// Add custom colors
theme: {
colors: {
customColor: 'purple',
},
// Add custom fonts
fonts: {
customFont: 'UHCSerif',
},
},
});
```
### Step 4: Viewing Theme
To view some of your theme updates, import some Abyss components into your project and see how they look!
```jsx sandbox
() => {
// Add Custom Theme
const theme = createTheme('uhc', {
theme: {
colors: {
customColor: '#8943fe',
},
fonts: {
customFont: 'UHCSerif',
},
},
});
return (
//Define Custom Theme in theme prop
Standard Text
Customized Text
);
};
```
Great job, you have successfully customized a theme!
---
id: styled-components
title: Styled Components
---
---
**Note:** We would appreciate any feedback on our tutorial guide. If you are stuck at any time, make sure to contact the Abyss Admiral assigned to your team. If they cannot help, send a help request on our [Contact Page](/mobile/contact-us/).
---
### Step 1: Create a Styled Screen
In Visual Studio Code, open the **my-new-app** project. From here, navigate to **products/mobile/src/screens** and create a new folder named `StyledScreen`. Within this new folder, create two new files named `index.ts` and `StyledScreen.tsx`.
```txt
products
└── mobile
└── src
└── screens
└── StyledScreen
├── index.ts
└── StyledScreen.tsx
```
### Step 2: Creating Styled Components
You can use the **styled** tool to style existing components or create new styled components. To learn more, check out our [styled](/mobile/tools/styled/) function.
In your **StyledScreen.tsx** file, add the following import statements:
```jsx
import React from 'react';
import { IconBrand, Card, Text, styled } from '@uhg-abyss/mobile';
```
We will create an information box to demonstrate how to work with styled-components.
After your import statements, insert the following code:
```jsx
const StyledCard = styled(Card, {
padding: '$sm',
flexDirection: 'row',
alignItems: 'center',
});
const StyledText = styled('Text', {
fontWeight: '$semibold',
});
```
### Step 3: Rendering Styled Components
This component uses the **StyledCard**, and **StyledText** components we created previously. There are other features available in the [styled](/mobile/tools/styled/) function to customize and edit your components to best fit your product's custom designs.
In the **StyledScreen.tsx** file, add the following code to your **StyledScreen** component:
```jsx
export const StyledScreen = () => {
return (
Average cost in your area: $980
);
};
```
### Step 4: Viewing Styled Components
At the end of this tutorial, the code in your **StyledScreen.tsx** file should look like this:
```jsx
import React from 'react';
import { styled, IconBrand, Card, Text } from '@uhg-abyss/mobile';
const StyledCard = styled(Card, {
padding: '$sm',
flexDirection: 'row',
alignItems: 'center',
});
const StyledText = styled('Text', {
fontWeight: '$semibold',
});
const StyledScreen = () => {
return (
Average cost in your area: $980
);
};
```
On your device, your StyledScreen should look like this:
```jsx live
// Create styled Card
const StyledCard = styled(Card, {
padding: '$sm',
flexDirection: 'row',
alignItems: 'center',
});
// Create styled Text
const StyledText = styled('Text', {
fontWeight: '$semibold',
});
const StyledScreen = () => {
return (
Average cost in your area: $980
);
};
render(() => {
return ;
});
```
Great job, you have successfully styled components!
---
id: versioning-guide
title: Versioning Guide
---
## Overview
Stability ensures that reusable components and libraries, tutorials, tools, and learned practices don't become obsolete unexpectedly. Stability is essential for the ecosystem around Abyss to thrive.
This document contains the practices that are followed to provide you with a leading-edge UI library, balanced with stability, ensuring that future changes are always introduced in a predictable way.
## Semantic Versioning
Abyss follows Semantic Versioning 2.0.0. Abyss version numbers have three parts: major.minor.patch. The version number is incremented based on the level of change included in the release.
- **Major releases** contain significant new features, some but minimal developer assistance is expected during the update. When updating to a new major release, you may need to run update scripts, refactor code, run additional tests, and learn new APIs.
- **Minor releases** contain important new features. Minor releases should be fully backward-compatible; no developer assistance is expected during update, but you can optionally modify your apps and libraries to begin using new APIs, features, and capabilities that were added in the release.
- **Patch releases** are low risk, contain bug fixes and small new features. No developer assistance is expected during update.
## Release Frequency
A regular schedule of releases helps you plan and coordinate your updates with the continuing evolution of Abyss. In general, you can expect the following release cycle:
- A **major** release typically every year for major changes.
- A **minor** releases every two weeks after each sprint.
- A **patch** release at any time for urgent bugfixes.
## Deprecation Practices
Sometimes **"breaking changes"**, such as the removal of support for select APIs and features, are necessary.
To make these transitions as easy as possible:
- The number of breaking changes is minimized, and migration tools provided when possible.
- The deprecation policy described below is followed, so that you have time to update your apps to the latest APIs and best practices.
## Deprecation Policy
- Deprecated features are announced in the changelog, and when possible, with warnings at runtime.
- When a deprecation is announced, recommended update path is provided.
- Existing use of a stable API during the deprecation period is supported, so your code will keep working during that period.
- Peer dependency updates (React) that require changes to your apps are only made in a major release.
## Tested React Native versions
---
id: workspace-setup
title: Workspace Setup
pagination_prev: null
---
## Overview
Developing modern JavaScript applications requires efficient, powerful, and extensible tooling. Consistency across developer machines is a priority when collaborating across highly distributed teams. The following is a guide for installing the preferred environment for JS development.

## Secure Groups
Visit secure.uhc.com to request permissions groups:
- **github_users**: To access github.com
- **Mac_Admin**: To install software for macOS users only
## VSCode Editor
To write code for UI projects, it is **highly recommended** that you download and install Visual Studio Code.

## VSCode Extensions
Recommended extensions will be suggested to you when you visit the VSCode Marketplace.
- ESLint - code syntax validator
ESLint is a JavaScript linting tool which is used for automatically detecting incorrect patterns found in ECMAScript/JavaScript code. It is used with the purpose of improving code quality, making code more consistent, and avoiding bugs. Rules can be configured to look for all kinds of discrepancies due to discouraged code patterns or formatting. Running a Linting tool over the source code helps to improve the quality and readability of the code.
- Prettier - code formatter
Prettier is very popular because it improves code readability and makes the coding style consistent for teams. Developers are more likely to adopt a standard rather than writing their own code style from scratch, so tools like Prettier will make your code look good without you ever having to dabble in the formatting.
## System Essentials
### Xcode
- Xcode Command Line Tools (Mac Only)
`xcode-select` contains necessary utilities for software development on macOS. Xcode's simulator will be used for viewing your app in an iOS environment.
```bash
xcode-select --install
```
**_After install, exit and restart Terminal (CMD + Q)_**
```
$ xcode-select --version
```
### Android Studio
Install Android Studio. The Virtual Device Manager will be use for viewing your app in an Android environment.
### Additional Tools
- oh-my-zsh >= 5.3.0 (optional)
`zsh` is an optional upgrade to the native shell which provides a delightful terminal experience.
```bash
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
```
**_After install, exit and restart Terminal (CMD + Q)_**
```bash
omz version
```
---
- node >= 16.0.0
`nvm` is a great tool for installing and upgrading versions of Node on your system.
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
```
**_After install, exit and restart Terminal (CMD + Q)_**
```bash
nvm --version
nvm install 16 && nvm use 16 && nvm alias default 16
```
**_After install, exit and restart Terminal (CMD + Q)_**
```
$ npm --version
$ npm config set registry https://repo1.uhc.com/artifactory/api/npm/npm-virtual
```
---
- git >= 2.0.0
`git` is a universal version control system for working collaboratively and efficiently.
```bash
git config --global user.id "YOUR_MS_ID"
git config --global user.email "YOUR_EMAIL@optum.com"
```
## Git Branch Names
Naming the branch you're working on helps repository maintainers understand the changes being made when the PR is opened. Using consistent branch name prefixes also allows build tools to automatically categorize the branches using labels. Branch names should be all lowercase (with the exception of US and DE) and include hyphens between words. All branches are divided into four groups:
- **story/#######** - Changes associated with a User Story, use the unique 7-digit number from Rally followed by a task description.
- **defect/#######** - Changes associated with a Defect, use the unique 7-digit number from Rally followed by a task description.
- **refactor/** - Changes to the repo that aren't documented in Rally are considered refactors, so use the task portion to add detail to your branch name.
- **release/** - Used specifically by build tools, this branch name is exclusive to release notes and documentation leading up to a new release.
Examples:
```
git checkout -b story/US2434515-developer-toolkit
git checkout -b defect/DE308703-button-accessibility
git checkout -b refactor/select-list-multi-docs
git checkout -b story/US1533842-use-loading-overlay
```
Branch Name Rules:
- Branch prefix must start with **story**, **defect**, **refactor**, or **release**
- Branch name must be only **lowercase letters, numbers, and hypens**
- **US###** and **DE###** are valid character exceptions
---
id: use-animation
category: Utilities
title: useAnimation
description: Use to create standardized animation types for Abyss Mobile components
design: https://www.figma.com/proto/wCMblLsq9TxAQvKzY3EfCt/branch/c6ve0gNrTGpdwBIuJehC3n/Abyss-Mobile?page-id=41951%3A175&type=design&node-id=41951-176&viewport=741%2C524%2C0.06&t=33q3lqs409fRYj6B-1&scaling=scale-down-width&starting-point-node-id=41951%3A176&show-proto-sidebar=1
---
```jsx
import { useAnimation } from '@uhg-abyss/mobile';
```
## Usage
`useAnimation` hook standardizes the animation types for Abyss components and simplifies additional customization. The hook returns `animate`, `value`, `interpolations`, as well as other Animated functions used throughout Abyss.
```jsx
export const useAnimation = (value: number, config: AnimationConfig) => {
...
return {
animate,
value: animatedValue,
interpolations,
createAnimation,
add,
subtract,
multiply,
divide,
delay,
parallel,
loop,
sequence,
};
};
```
## Animate
The `animate` function requires a toValue be passed in, with the option for overrides and a callback function.
```jsx
const animate = (
toValue: number,
configOverride?: Partial,
callback?: Animated.EndCallback
) => {
return createAnimation(toValue, configOverride).start(callback);
};
```
```jsx live
() => {
const { animate, value, interpolations } = useAnimation(1, {
easing: 'gentle',
interpolations: {
background: {
inputRange: [0.95, 1],
outputRange: ['$primary1', '$info1'],
tokenType: 'colors',
},
},
});
const AnimatedButton = styled(Animated.createAnimatedComponent(Pressable), {
justifyContent: 'center',
alignItems: 'center',
padding: '$md',
borderRadius: 100,
alignSelf: 'center',
});
return (
{
animate(0.95);
}}
onPressOut={() => {
animate(1);
}}
style={{
transform: [{ scale: value }],
background: interpolations.background,
}}
>
Press Me
);
};
```
### Overrides
By default the animation type is set to `'timing'`. Additional types supported are `'spring'` and `'instant'` with the following animation config open to override:
```jsx
interface AnimationConfig extends BaseAnimationConfig {
type?: 'spring' | 'timing' | 'instant';
interpolations?: Record;
delay?: number | undefined;
// timing
easing?: Easing;
duration?: number | undefined;
// spring
overshootClamping?: boolean | undefined;
restDisplacementThreshold?: number | undefined;
restSpeedThreshold?: number | undefined;
velocity?: number | { x: number, y: number } | undefined;
bounciness?: number | undefined;
speed?: number | undefined;
tension?: number | undefined;
friction?: number | undefined;
stiffness?: number | undefined;
mass?: number | undefined;
damping?: number | undefined;
}
```
## Interpolations
The `interpolations` prop can take in multiple interpolation objects to be used on the same animated value.
```jsx
const { value, animate, interpolations } = useAnimation(1, {
easing: 'gentle',
interpolations:{
backgroundColor: {
inputRange: [0.95, 1],
outputRange: ['$info1', '$primary1']
tokenType: 'colors',
},
opacity: {
inputRange: [0.95, 1],
outputRange: [0, 1]
},
}
});
```
```jsx live
() => {
const { animate, value, interpolations } = useAnimation(1, {
easing: 'gentle',
interpolations: {
background: {
inputRange: [0.95, 1],
outputRange: ['#00BED5', '$primary1'],
tokenType: 'colors',
},
opacity: {
inputRange: [0.95, 1],
outputRange: [0.8, 1],
},
},
});
const Label = styled(Animated.Text, {
color: '$white',
fontSize: '$xs',
lineHeight: '$xs',
fontWeight: '$bold',
marginTop: '$xs',
});
const AnimatedTabButton = styled(
Animated.createAnimatedComponent(Pressable),
{
justifyContent: 'center',
alignItems: 'center',
padding: '$md',
cornerRadius: 10,
alignSelf: 'center',
}
);
return (
{
animate(0.95);
}}
onPressOut={() => {
animate(1);
}}
style={{
transform: [{ scale: value }],
background: interpolations.background,
}}
>
);
};
```
## Additional Functionality
Other Animated methods currently used throughout Abyss components can also be returned.
```jsx
const parallel = (
animations: Animated.CompositeAnimation[],
parallelConfig?: Animated.ParallelConfig
) => {
return Animated.parallel(animations, parallelConfig);
};
const loop = (
animation: Animated.CompositeAnimation,
loopConfig?: Animated.LoopAnimationConfig
) => {
return Animated.loop(animation, loopConfig);
};
const sequence = (animations: Animated.CompositeAnimation[]) => {
return Animated.sequence(animations);
};
const delay = (time: number) => {
return Animated.delay(time);
};
const add = (num: number) => {
return Animated.add(animatedValue, num);
};
const subtract = (num: number) => {
return Animated.subtract(animatedValue, num);
};
const divide = (num: number) => {
return Animated.divide(animatedValue, num);
};
const multiply = (num: number) => {
return Animated.multiply(animatedValue, num);
};
```
## Accessibility Integration
The `useAnimation` hook has built-in integration with the [`useReduceMotion`](/mobile/hooks/use-reduce-motion) hook. This ensures that animated components automatically respect the user's "Reduce Motion" accessibility setting without requiring additional handling.
When "Reduce Motion" is enabled, the `useAnimation` hook adjusts the animation type to `'instant'`, minimizing motion effects. This makes it easier to create accessible components that align with user preferences.
---
id: use-device-orientation
category: Utilities
title: useDeviceOrientation
description: Used to retrieve the orientation of the mobile device
---
```jsx
import { useDeviceOrientation } from '@uhg-abyss/mobile';
```
## Usage
`useDeviceOrientation` measures the width and height of the screen and returns `'landscape'` or `'portrait'`.
```jsx
const orientation = useDeviceOrientation();
const iconSize = orientation === 'landscape' ? 20 : 24;
return ;
```
---
id: use-form
category: State Management
title: useForm
description: useForm is a hook for defining, validating and submitting forms.
sourceIsTS: true
---
```jsx
import { useForm } from '@uhg-abyss/mobile';
```
## Usage
The `useForm` hook is used to define, validate, and submit forms in Abyss. Use `useForm` along with the [FormProvider](/mobile/ui/form-provider)
component in order to better manage your forms and fully utilize the capabilities of form management within Abyss.
Abyss components that can be used with useForm have a `model` prop that is used to bind the component to the form state.
Validations can be defined on each component using the `validations` prop, which accepts an object with validation rules.
If a component fails validation, it will display an error message based on the validation rules defined.
When a form is successfully submitted, the function passed to the `onSubmit` prop will be called with the form data.
```jsx live
() => {
const form = useForm();
const onSubmit = (data) => {
// Do something on submit
alert(`FormData: ${JSON.stringify(data)}`);
};
return (
);
};
```
## Default Values
The defaultValues prop populates the entire form with default values. It supports both synchronous and asynchronous assignments of default values.
```jsx live
() => {
// Default Values Passed into useForm
const form = useForm({
defaultValues: {
firstName: 'John',
lastName: 'Doe',
},
});
const onSubmit = (data) => {
alert(`FormData: ${JSON.stringify(data)}`);
};
return (
);
};
```
## Form State
This object contains information about the form state. If you want to subscribe to formState via useEffect, make sure that you place the entire formState in the optional array.
```jsx
const form = useForm();
const {
errors, // An object with field errors
isDirty, // Set to true after the user modifies any of the inputs.
isValid, // Set to true if the form doesn't have any errors.
isValidating, // Set to true during validation.
isSubmitting, // true if the form is currently being submitted; false if otherwise.
isSubmitted, // Set to true after the form is submitted.
isSubmitSuccessful, // Indicate the form was successfully submitted without any Promise rejection or Error being thrown within the handleSubmit callback.
submitCount, // Number of times the form was submitted.
touchedFields, // An object containing all the inputs the user has interacted with.
dirtyFields, // An object with the user-modified fields.
} = form.formState;
```
## Watch
This will watch specified inputs and return their values. It is useful for determining what to render.
```jsx live
() => {
const form = useForm();
const onSubmit = (data) => {
alert(`FormData: ${JSON.stringify(data)}`);
};
// Watch one field
const WatchField = form.watch('firstName');
// Target specific fields by their names
const WatchFields = form.watch(['firstName', 'lastName']);
// Watch everything by passing no arguments
const WatchAllFields = form.watch();
return (
Watch One Field: {JSON.stringify(WatchField)}Watch Multiple Fields: {JSON.stringify(WatchFields)}Watch All Fields: {JSON.stringify(WatchAllFields)}
);
};
```
## Handle Submit
This function will receive the form data if form validation is successful.
```jsx live
() => {
const form = useForm({
defaultValues: {
firstName: 'John',
lastName: 'Doe',
},
});
const onSubmit = (data, e) => alert('onSubmit');
const onError = (errors, e) => alert('onError');
return (
);
};
```
## Validate Model
This function will receive the model data if form validation is successful.
```jsx live
() => {
const form = useForm({
defaultValues: {
firstName: 'John',
},
});
const handleValidateFirst = () => {
form.validate(
'firstName',
(data) => {
alert(`FormData: ${JSON.stringify(data)}`);
},
(error) => {
delete error.ref;
alert(`Error: ${JSON.stringify(error)}`);
}
);
};
const handleValidateLast = () => {
form.validate(
'lastName',
(data) => {
alert(`FormData: ${JSON.stringify(data)}`);
},
(error) => {
delete error.ref;
alert(`Error: ${JSON.stringify(error)}`);
}
);
};
return (
);
};
```
## Set Error
The function allows you to manually set one or more errors.
```jsx live
() => {
const form = useForm({
defaultValues: {
firstName: 'John',
lastName: 'Doe',
},
});
// Set single error
const setSingleError = () => {
form.setError('firstName', {
type: 'manual',
message: 'There is an error with your name!',
});
};
// Set multiple errors
const setMultipleErrors = () => {
[
{
type: 'manual',
name: 'firstName',
message: 'Check first name',
},
{
type: 'manual',
name: 'lastName',
message: 'Check last name',
},
].forEach(({ name, type, message }) => {
form.setError(name, { type, message });
});
};
// Set error for single field errors
React.useEffect(() => {
form.setError('firstName', {
types: {
required: 'This is required',
minLength: 'This is minLength',
},
});
}, []);
return (
);
};
```
## Clear Errors
This function can manually clear errors in the form.
```jsx live
() => {
const form = useForm({
defaultValues: {
firstName: 'John',
lastName: 'Doe',
phone: '555-555-5555',
},
});
const resetErrors = () => {
[
{
type: 'manual',
name: 'firstName',
message: 'Required',
},
{
type: 'manual',
name: 'lastName',
message: 'Required',
},
{
type: 'manual',
name: 'phone',
message: 'Required',
},
].forEach(({ name, type, message }) => {
form.setError(name, { type, message });
});
};
// Clear single error
const clearSingleErrors = () => {
form.clearErrors('firstName');
};
// Clear multiple errors
const clearMultipleErrors = () => {
form.clearErrors(['firstName', 'lastName']);
};
// Clear all errors
const clearAllErrors = () => {
form.clearErrors();
};
return (
);
};
```
## Get Values
An optimized helper for reading form values. The difference between watch and getValues is that getValues will not trigger re-renders or subscribe to input changes.
```jsx live
() => {
const form = useForm({
defaultValues: {
firstName: 'John',
lastName: 'Doe',
phone: '555-555-5555',
},
});
// Read an individual field value by name
const singleValue = form.getValues('firstName');
// Read multiple fields by name
const multipleValues = form.getValues(['firstName', 'lastName']);
// Reads all form values
const allValues = form.getValues();
return (
Single Value: {JSON.stringify(singleValue)}
Multiple Values: {JSON.stringify(multipleValues)}
All Values: {JSON.stringify(allValues)}
);
};
```
## Trigger
Manually triggers form or input validation. This method is also useful when you have dependent validation (input validation depends on another input's value).
```jsx live
() => {
const form = useForm();
// Trigger one input to validate
const triggerSingle = () => {
form.trigger('firstName');
};
// Trigger multiple inputs to validate
const triggerMultiple = () => {
form.trigger(['firstName', 'lastName']);
};
// Trigger entire form to validate
const triggerAll = () => {
form.trigger();
};
const clearErrors = () => {
form.clearErrors();
};
return (
);
};
```
## Cross-Field Validation Example
```jsx live
() => {
const form = useForm();
const onSubmit = (data) => {
console.log('data', data);
};
return (
{
const checkValue = form.getValues('middleName-check');
if (!checkValue && !v) {
return 'Required';
}
},
}}
showValidations={false}
/>
{
form.trigger('middleName');
}}
/>
);
};
```
## Additional Documentation
`@uhg-abyss/mobile/hooks/useForm` is a built on top of the `useForm` hook from React Form Hook.
**Note:** You should be using Abyss's `useForm` hook when using Abyss components and **not** react hook forms.
---
id: use-reduce-motion
category: Utilities
title: useReduceMotion
description: Used within animated components to respect a user's accessibility preferences.
---
```jsx
import { useReduceMotion } from '@uhg-abyss/mobile';
```
## Usage
The `useReduceMotion` hook is a custom hook designed to determine whether the user has enabled the "Reduce Motion" accessibility setting on their device. This setting is often used by individuals who prefer to minimize animations and motion effects for accessibility or comfort reasons.
The hook returns an object `{reducedMotionEnabled}` with the boolean value:
- `true`: "Reduce Motion" is enabled.
- `false`: "Reduce Motion" is disabled.
When reduce motion is enabled, this hook can be used to adjust animation behavior.
```jsx live
const AnimatedContainer = styled('Animated.View', {
padding: '$lg',
backgroundColor: '$primary1',
width: 100,
height: 100,
margin: '$lg',
});
const SequentialAnimation = () => {
const { reducedMotionEnabled } = useReduceMotion();
const animatedValues = useRef([
new Animated.Value(1),
new Animated.Value(1),
new Animated.Value(1),
]).current;
useEffect(() => {
const createAnimation = (index) =>
Animated.sequence([
Animated.timing(animatedValues[index], {
toValue: 1.4,
duration: 500,
useNativeDriver: false,
}),
Animated.timing(animatedValues[index], {
toValue: 1,
duration: 500,
useNativeDriver: false,
}),
]);
const loopAnimation = Animated.loop(
Animated.stagger(250, [
createAnimation(0),
createAnimation(1),
createAnimation(2),
])
);
loopAnimation.start();
return () => loopAnimation.stop();
}, []);
return (
{animatedValues.map((animatedValue, index) => (
))}
);
};
render(() => {
return ;
});
```
## Enabling Reduce Motion by Device
### iOS
- Open the Settings app
- Select Accessibility
- Choose Motion
- Toggle the switch next to Reduce Motion to on
### Android
- Open the Settings app
- Select Accessibility
- Depending on your Android version, look for Remove Animations (or similar)
### Windows
- Open Settings
- Select Accessibility
- Go to Visual Effects
- Toggle Animation Effects to off
### Mac OS
- Open System Settings
- Select Accessibility
- Choose Display
- Toggle Reduce Motion to on
## Additional Notes
- The hook listens for changes to the "Reduce Motion" setting and updates its value dynamically.
- The [`useAnimation`](/mobile/hooks/use-animation) hook integrates `useReduceMotion` directly, ensuring that animated components automatically respect the user's motion preferences without requiring additional handling.
- Use this hook to create a more inclusive and accessible experience for users who prefer minimal motion effects. Please refer to accessibility guidelines for animations when creating new components.
- WCAG standards:
-
iOS
-
Android
---
id: use-set-focus
category: Utilities
title: useSetFocus
description: Used to set accessibility focus on a specified element.
---
```jsx
import { useSetFocus } from '@uhg-abyss/mobile';
```
## Usage
The hook returns a function that consumes a ref object. Simply call said function to set the screen reader focus.
```jsx
const setFocus = useSetFocus();
const myRef = useRef(null);
return (
<>
Link to be focused
>
);
```
## Example
In the example below, Android's Talkback can be seen focusing the bottom text when the `Focus Text` button is pressed.
---
id: use-style-sheet
category: Styling
title: useStyleSheet
description: Used to parse styles from a StyleSheet
---
```jsx
import { useStyleSheet } from '@uhg-abyss/mobile';
```
The `useStyleSheet` hook helps to parse the additional functionality from the Abyss [StyleSheet](/mobile/ui/style-sheet).
## Usage
```tsx
useStyleSheet(styles: object): object
```
Take a look at StyleSheet below:
```jsx
const styles = StyleSheet.create({
container: {
padding: '$xs * 4px',
margin: '$fontScale',
},
label: {
color: '$gray4',
fontWeight: '$bold',
fontSize: '$lg',
marginVertical: '$md * 2',
fontFamily: '$heading',
},
box: {
backgroundColor: '$interactive1',
borderColor: '$error1',
borderRadius: '$md * $sm',
borderWidth: 4,
width: '6rem',
height: '48px * 3',
marginBottom: '32px - 0.75rem',
'@media (min-width: 767px)': {
width: '12rem',
},
},
});
```
There's a lot of code that is unfamiliar to the normal StyleSheet. Above, there are _**media queries**_,
_**tokens**_, _**operations**_, _**rem values**_, and _**pixel values**_, which normally would not be able to be parsed by React
Native core component. This is where the `useStyleSheet` hook comes in. By using the hook, we can parse these
value into value that the core component can understand.
```jsx live
const themedStyles = StyleSheet.create({
container: {
padding: '$xs * 4px',
margin: '$fontScale',
},
label: {
color: '$gray4',
fontWeight: '$bold',
fontSize: '$lg',
marginVertical: '$md * 2',
fontFamily: '$heading',
},
box: {
backgroundColor: '$interactive1',
borderColor: '$error1',
borderRadius: '$md * $sm',
borderWidth: 4,
width: '6rem',
height: '48px * 3',
marginBottom: '32px - 0.75rem',
'@media (min-width: 767px)': {
width: '12rem',
},
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
Parsed Styles{JSON.stringify(styles, null, 4)}Original Styles{JSON.stringify(themedStyles, null, 4)}
);
});
```
---
id: use-token
category: Utilities
title: useToken
description: Used to get values mapped to tokens.
---
```jsx
import { useToken } from '@uhg-abyss/mobile';
```
This hook returns a function that is used to get the style value associated with a token defined in the theme. Use this whenever you want to pass in a prop with the value of a token string instead of the associated token value.
## Properties
```typescript
type TokenKey = 'colors' | 'space' | 'sizes' | 'fontSizes' | 'lineHeights' | 'fontWeights' | 'fonts' | 'radii';
interface TokenConfig {
retain?: boolean;
};
useToken(key: TokenKey, config?: TokenConfig)
```
## Usage
The `key` argument corresponds to the upper level category inside the theme. Start with defining a function and passing it the string of the token key. You can then use that function to pass in your token element and get the associated value.
A hex value can also be passed in as a `token` and it will be returned as is|unless set not to.
```jsx
const theme = {
theme: {
colors: {...},
space: {...},
fontSizes: {...},
fonts: {...},
},
};
const getColorToken = useToken('colors');
const color = getColorToken('$primary1');
```
## Example
```jsx live
() => {
const getColorToken = useToken('colors');
const color = getColorToken('$interactive3');
const getSpaceToken = useToken('space');
const space = getSpaceToken('$md');
return (
Abyss Design System
);
};
```
### Defaults
By default, the `useToken` hook uses the passed in value if the token is not found/is invalid. This
allows it to take hex and string values and return them as is.
Using the `config` parameter, you can pass in `{retain: false}` to require tokenized values.
```jsx live
() => {
const getSpaceToken = useToken('space');
const space = getSpaceToken('$md');
const getColorToken = useToken('colors');
const color = getColorToken('#D9E9FA');
const color2 = getColorToken('gray');
const getColorToken2 = useToken('colors', { retain: false });
const color3 = getColorToken2('#D9E9FA');
return (
Abyss Design SystemAbyss Design SystemAbyss Design System
);
};
```
---
id: use-translate
category: Utilities
title: useTranslate
description: Used to get the translated string from the i18n object.
---
```jsx
import { useTranslate } from '@uhg-abyss/mobile/hooks/useTranslate';
```
The `useTranslate` hook is used to get the translated string from the Abyss [i18n](/mobile/utilities/i18n) object.
## Usage
```typescript
interface I18nTranslate {
t: (key: string, replacements?: object) => string;
i18n: object;
}
useTranslate(key: string, replacements?: object): I18nTranslate
```
The `key` argument corresponds to the key in the i18n object. The `replacements` argument is an object that contains the values to replace in the translated string.
Let's use an example to illustrate how to use the `useTranslate` hook. In the [TextField](/mobile/ui/text-field) component, we have a text block that displays the remaining characters available
to be typed in the text field. We can get that value with the key `TextField.charactersRemaining`.
```jsx live-expanded
() => {
const { t } = useTranslate();
return {t('TextField.charactersRemaining')};
};
```
If we want to replace the value of the remaining characters, we can pass in the `replacements` object with the key `count`.
Replacement values should always appear in double curly braces, (e.g. `{{count}}`).
```jsx live-expanded
() => {
const { t } = useTranslate();
return {t('TextField.charactersRemaining', { count: 10 })};
};
```
We can also use the `useTranslate` hook to get the translated string from the i18n object.
```jsx live-expanded
() => {
const { i18n } = useTranslate();
return {i18n.TextField.charactersRemaining};
};
```
---
id: about
slug: /mobile/about
title: About Abyss
---
## What is Abyss?
## How Abyss works
## We support adoption
## Guiding Principles
## We Maintain Assets
## The Abyss Team
---
id: contact-us
slug: /mobile/contact-us
title: Contact Us
hide_table_of_contents: true
---
## Support
## Requests
---
id: disclaimer
slug: /mobile/disclaimer
title: Mobile Components Disclaimer
---
As a note, these components were developed for use in a mobile application environment. For your convenience, we created documentation and interactive examples on our Abyss site. We have tried our best to accurately show the functionality and style of each component on these pages, but you may notice some differences and limitations as the optimal platform for viewing and interacting with these components is a mobile device.
A few examples are described below:
- [Date Input](/mobile/ui/date-input) requires native code, so this component is only supported on iOS and Android. There are no interactive examples in the documentation; only recordings of each feature are available. To fully interact with the date and time pickers you will need to import the component within a mobile development environment.
- [Modal](/mobile/ui/modal), and any component that uses Modal, takes up the entire browser window when opened. While it is intended to take up the entire phone screen as well, the content on the modal will fill much more space when used on a mobile device than it does in the browser window.
---
id: overview
slug: /mobile/overview
title: Overview
hide_table_of_contents: true
---
##
---
id: product-roadmap
slug: /mobile/product-roadmap
title: Product Roadmap
---
##
For 2024, please see details below that outline the Goals/Themes, Solutions Capabilities, and PI Plans for the Abyss Design System.
Please note, this page will be updated at the beginning of each PI.
## Abyss Business Objectives for 2024
## Solution Capabilities
To achieve greater adoption and consistency, below are the overarching Solution Capabilities for Abyss that outline some more specific initiatives the team is working toward. For additional details, check out our Aha Board on Solution Capabilities.
## Abyss Mobile Development
As we continue work to build out Abyss Mobile, below is a breakdown of the
Solution Capabilities and high-level PI plan for the planned work. To see
more specific details on the status of Abyss Mobile, please review our UHC Design System Status and Migration Plan PowerPoint.
### PI Plan
- Further breaking down our Solution Capabilities, below is our outline for current, upcoming PI Plans and the key features being addressed in each of the 5 sprints.
- For additional details on items that will fall under each of these Solution Capabilities, check out our Aha Feature board
** Note: The items below are subject to change as priorities shift throughout each sprint. **
## Abyss Mobile Design
### PI Plan
- Further breaking down our Solution Capabilities, below is our outline for current, upcoming PI Plans and the key features being addressed in each of the 5 sprints.
** Note: The items below are subject to change as priorities shift throughout each sprint. **
---
id: releases
slug: /mobile/releases
title: Releases
---
---
id: accessibility
title: Accessibility
---
## Overview
## Interactive components
```jsx sandbox
{
component: 'Button',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'solid', value: 'solid' },
{ label: 'outline', value: 'outline' },
{ label: 'ghost', value: 'ghost' },
],
},
{
prop: 'size',
type: 'string',
},
{
prop: 'children',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean'
},
],
}
```
## Color Contrast
```jsx render
```
## Icons
### Meaningful or Control Icons
If the icon is being used in a setting where it is the only element providing meaning, then that same meaning should be conveyed to screen reader users. The below implementation provides examples of situations in which the property `isScreenReadable` should be set to true and the `title` property is required and should describe the purpose of the image.
Example 1: An alert icon is used to convey a sense of urgency; there is adjacent text (“There is a data outage”) but the text doesn't include any words that convey urgency. So, in this case, the icon should have a text alternative such as “Alert” or “Warning”.
```jsx live
There is a data outage
```
Example 2: An “X” material icon is used as a close button on a modal dialog. There
is no adjacent text, so the icon should have a text alternative of “close” or “close
window”.
```jsx live
```
### Decorative Icons
If the icon is being used in a setting in which it is just a decorative element (which is the default case for icons), then the icon should be ignored by screen readers. The below implementation provides example of which situations would be classified as decorative. Since the default of `isScreenReadable` is set to false no specific changes need to be made for decorative icons.
Example 1: An alert icon is used next to an urgent message and the word “Alert” is included in the adjacent text. In this case, the icon becomes decorative in nature and should be ignored by screen readers.
```jsx live
Alert: There is a data outage
```
Example 2: An “X” material icon is used as a close button on a modal dialog; the
word “Close” appears to the right of the button. In this case, the icon should be
considered decorative and ignored by screen readers.
```jsx live
Close
```
## Dynamic Type
Abyss Mobile standards for dynamic types are as follows:
- We scale typography and icons in increments of 11.8%.
-
Figma
shows scaling examples at xxxLarge and AX5.
- We do not scale images, brand icons, or illustrations.
- See [IconBrand](/mobile/brand/uhc/icon-brand/) and [IllustrationBrand](/mobile/brand/uhc/illustration-brand/) for more details.
- We also do not scale border-weight or border-radius.
- Some components, such as framing components and certain graphic elements, freeze at xxxLarge (3XL).
### Scale
```jsx render
Scale
Percent
XL
110%
XXL
120%
XXXL
130%
AX1
179%
AX2
214%
AX3
264%
AX4
314%
AX5
357%
```
## Additional Resources
---
id: product-inclusion
title: Product Inclusion
---
## Mission statement
## Product inclusion principles
## Product inclusion checklist
## Product inclusion audit tool
## Contact us
---
id: product-resources
title: Product Resources
---
## Overview
## How does Abyss work?
## Versioning
## Branding
## Accessibility
## Support
---
id: create-theme
category: Util
title: createTheme
description: Tool to create and modify themes.
---
```jsx
import { createTheme } from '@uhg-abyss/mobile';
```
The tool `createTheme` allows for the creation of preset themes and allows you to override those themes to fit your design needs. `createTheme` is used in conjunction with [ThemeProvider](/mobile/ui/theme-provider).
## Properties
```typescript
createTheme(
theme: string,
override?: object,
): object;
```
## Usage
`createTheme` takes two arguments. The first argument is the choice of a default theme. There are currently 4 themes available: `"uhc"`, `"uhg"`, `"optum"`, and `"abyss"`. If no theme is chosen, it will fall back to the default `"abyss"` theme. The second argument is any overrides you wish to apply to the chosen base theme.
```jsx
import { ThemeProvider, createTheme } from '@uhg-abyss/mobile';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
const themeOverride = {
theme: {
colors: {...},
space: {...},
fontSizes: {...},
fonts: {...},
fontWeights: {...},
lineHeights: {...},
letterSpacings: {...},
sizes: {...},
borderWidths: {...},
borderStyles: {...},
radii: {...},
shadows: {...},
zIndices: {...},
transitions: {...},
},
deprecatedOptumIcons: boolean, // see below for details
};
const theme = createTheme('uhc', themeOverride);
const App = () => {
return ...;
};
AppRegistry.registerComponent(appName, () => App);
```
## Example
Here is an example of a theme created with a custom override. A token named `customColor` will be added to the color tokens.
```jsx
const theme = createTheme('uhc', {
theme: {
colors: {
customColor: '#ff612b', // orange
},
},
});
```
```jsx live
() => {
const theme = createTheme('uhc', {
theme: {
colors: {
customColor: '#ff612b',
},
},
});
return (
Sample Text
);
};
```
## Important: Optum Icons Deprecation
The Optum icons used in `IconBrand` have been updated in [Abyss v1.54.0](https://github.com/uhc-tech/abyss/releases/tag/v1.54.0). The new icons correspond to the icons available on the Optum Brand website.
The old icons will remain available for the time being and can be enabled by setting the `deprecatedOptumIcons` property to `true` in the `themeOverride` object.
```jsx
const themeOverride = {
deprecatedOptumIcons: true,
};
```
---
id: create-bottom-tab-navigator
category: Navigation
title: createBottomTabNavigator
description: A simple tab bar on the bottom of the screen that lets you switch between different routes.
---
```jsx
import { createBottomTabNavigator } from '@uhg-abyss/mobile';
```
The most common style of navigation in mobile apps is tab-based navigation. A simple tab bar on the bottom of the screen lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.
Calling the `createBottomTabNavigator` function creates a Tab object with `Screen` & `Navigator` properties.
All tab screen must be wrapped around a Tab.Navigator object component. All screens must have a `name` and `component` passed in as props.
## Example
```jsx
const Tab = createBottomTabNavigator();
const Screen = ({ route }) => {
return (
This is the {route.name} page
);
};
export default function App() {
return (
(
),
}}
/>
(
),
}}
/>
(
),
}}
/>
(
),
}}
/>
);
}
```
```jsx render:phone-dark
() => {
const [page, setPage] = useState('home');
const Container = styled('View', {
flexGrow: 1,
});
const Header = styled('View', {
backgroundColor: '$primary1',
width: '100%',
paddingTop: 30,
});
const HeaderContent = styled('View', {
margin: '$sm',
flexDirection: 'row',
justifyContent: 'center',
});
const Title = styled('Text', {
color: '$white',
fontWeight: '$semibold',
textTransform: 'capitalize',
});
const ContentArea = styled('View', {
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
});
const TabBar = styled('View', {
backgroundColor: '$primary1',
height: 60,
display: 'flex',
color: '$white',
paddingBottom: 16,
paddingTop: 8,
flexDirection: 'row',
borderTopLeftRadius: 12,
borderTopRightRadius: 12,
});
const TabBarItem = styled('Pressable', {
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
});
const ContentText = styled('Text', {});
const TabLabel = styled('Text', {
fontSize: '$2xs',
color: '$white',
variants: {
active: {
true: { fontWeight: '$bold' },
},
},
});
return (
{page.split('_').join(' ')}
{page === 'home' && This is the Home page}
{page === 'my_plan' && (
This is the My Plan page
)}
{page === 'find_care' && (
This is the Find Care page
)}
{page === 'menu' && This is the Menu page}
setPage('home')}
>
{({ pressed }) => {
const active = page === 'home';
return (
<>
Home
>
);
}}
setPage('my_plan')}
>
{({ pressed }) => {
const active = page === 'my_plan';
return (
<>
My Plan
>
);
}}
setPage('find_care')}
>
{({ pressed }) => {
const active = page === 'find_care';
return (
<>
Find Care
>
);
}}
setPage('menu')}
>
{({ pressed }) => {
const active = page === 'menu';
return (
<>
Menu
>
);
}}
);
};
```
### Props
The `Tab.Navigator` component accepts following props:
#### `id`
Optional unique ID for the navigator. This can be used with `navigation.getParent` to refer to this navigator in a child navigator.
#### `initialRouteName`
The name of the route to render on first load of the navigator.
#### `screenOptions`
Default options to use for the screens in the navigator.
#### `backBehavior`
This controls what happens when `goBack` is called in the navigator. This includes pressing the device's back button or back gesture on Android.
It supports the following values:
- `firstRoute` - return to the first screen defined in the navigator (default)
- `initialRoute` - return to initial screen passed in `initialRouteName` prop, if not passed, defaults to the first screen
- `order` - return to screen defined before the focused screen
- `history` - return to last visited screen in the navigator; if the same screen is visited multiple times, the older entries are dropped from the history
- `none` - do not handle back button
#### `detachInactiveScreens`
Boolean used to indicate whether inactive screens should be detached from the view hierarchy to save memory. This enables integration with [react-native-screens](https://github.com/software-mansion/react-native-screens). Defaults to `true`.
#### `sceneContainerStyle`
Style object for the component wrapping the screen content.
#### `tabBar`
Function that returns a React element to display as the tab bar.
Note that you **cannot** use the `useNavigation` hook inside the `tabBar` since `useNavigation` is only available inside screens. You get a `navigation` prop for your `tabBar` which you can use instead:
### Options
The following options can be used to configure the screens in the navigator. These can be specified under `screenOptions` prop of `Tab.navigator` or `options` prop of `Tab.Screen`.
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
#### `tabBarLabel`
Title string of a tab displayed in the tab bar or a function that given `{ active: boolean, color: string }` returns a React.Node, to display in tab bar. When undefined, scene `title` is used. To hide, see `tabBarShowLabel`.
#### `tabBarShowLabel`
Whether the tab label should be visible. Defaults to `true`.
#### `tabBarLabelPosition`
Whether the label is shown below the icon or beside the icon.
- `below-icon`: the label is shown below the icon (typical for iPhones)
- `beside-icon` the label is shown next to the icon (typical for iPad)
By default, the position is chosen automatically based on device width.
#### `tabBarLabelStyle`
Style object for the tab label.
#### `tabBarIcon`
React.ReactNode or a function that given `{ active: boolean }` returns a React.ReactNode, to display in the tab bar.
#### `showTabBarBadge`
Whether or not the badge should be visible on the tab icon.
#### `showTabBarBadgeOnActive`
Whether or not the badge should be visible on the tab icon when it is active.
#### `tabBarBadgeLabel`
Text to show in a badge on the tab icon. Accepts a `string` or a `number`.
#### `tabBarBadgeOffset`
Offset for the badge on the tab icon.
#### `tabBarAccessibilityLabel`
Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.
#### `tabBarTestID`
ID to locate this tab button in tests.
#### `tabBarActiveTintColor`
Color for the icon and label in the active tab.
#### `tabBarInactiveTintColor`
Color for the icon and label in the inactive tabs.
#### `tabBarActiveBackgroundColor`
Background color for the active tab.
#### `tabBarInactiveBackgroundColor`
Background color for the inactive tabs.
#### `tabBarActiveLabelWeight`
Font weight for the label in the active tab.
#### `tabBarInactiveLabelWeight`
Font weight for the label in the inactive tabs.
#### `tabBarItemStyle`
Style object for the tab item container.
#### `tabBarStyle`
Style object for the tab bar. You can configure styles such as background color here.
To show your screen under the tab bar, you can set the `position` style to absolute:
```js
```
## Dynamic Type
Text and icons scale to 3XL. Any additional text or icon passed in should set `maxFontSizeMultiplier={1.3}`.
---
id: create-stack-navigator
category: Navigation
title: createStackNavigator
description: Provides a way for your apps to transition between screens where each new screen is placed on top of a stack.
---
```jsx
import { createStackNavigator } from '@uhg-abyss/mobile';
```
This navigator uses the native APIs `UINavigationController` on iOS and `Fragment` on Android so that navigation built with `createStackNavigator` will behave exactly the same and have the same performance characteristics as apps built natively on top of those APIs.
`Screen` components are used to configure various aspects of screens inside a navigator.
A `Screen` is returned from a createStackNavigator function:
```jsx
const Stack = createStackNavigator(); // Stack contains Screen & Navigator properties
```
After creating the navigator, it can be used as children of the Navigator component:
```jsx
function MyStack() {
return (
);
}
```
You need to provide at least a name and a component to render for each screen.
### Options
The following options can be used to configure the screens in the navigator.
These can be specified under `screenOptions` prop of `Tab.Navigator` or `options` prop of `Tab.Screen`.
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
#### `lazy`
Whether the screen should render the first time it's accessed. Defaults to `true`. Set it to `false` if you want to render the screen on initial render.
#### `unmountOnBlur`
Whether this screen should be unmounted when navigating away from it. Unmounting a screen resets any local state in the screen as well as state of nested navigators in the screen. Defaults to `false`.
Normally, we don't recommend enabling this prop as users don't expect their navigation history to be lost when switching tabs. If you enable this prop, please consider if this will actually provide a better experience for the user.
#### `freezeOnBlur`
Boolean indicating whether to prevent inactive screens from re-rendering. Defaults to `false`.
Defaults to `true` when `enableFreeze()` from `react-native-screens` package is run at the top of the application.
Requires `react-native-screens` version >=3.16.0.
### Header related options
You can find the list of header related options [here](elements.md#header). These [options](screen-options.md) can be specified under `screenOptions` prop of `Tab.navigator` or `options` prop of `Tab.Screen`. You don't have to be using `@react-navigation/elements` directly to use these options, they are just documented in that page.
In addition to those, the following options are also supported in bottom tabs:
#### `header`
Custom header to use instead of the default header.
This accepts a function that returns a React Element to display as a header. The function receives an object containing the following properties as the argument:
- `navigation` - The navigation object for the current screen.
- `route` - The route object for the current screen.
- `options` - The options for the current screen.
Example:
```jsx
import { getHeaderTitle } from '@react-navigation/elements';
header: ({ navigation, route, options }) => {
const title = getHeaderTitle(options, route.name);
return ;
};
```
To set a custom header for all the screens in the navigator, you can specify this option in the `screenOptions` prop of the navigator.
#### `headerTitle`
String or React Element that returns a React Element to be used as the title of the header. Defaults to scene `title`
#### `headerTitleAlign`
How to align the header title. Possible values:
- `left`
- `center`
Defaults to `center` on iOS and `left` on Android.
#### `truncateTitle`
Allows the title to be truncated. Defaults to false.
#### `headerEyebrow`
String, React Element, or function that returns a React Element to be used as the eyebrow of the header.
The eyebrow is placed above the title.
#### `headerSubtitle`
String, React Element, or function that returns a React Element to be used as the subtitle of the header.
The subtitle is placed below the title.
#### `headerLeft`
React Element or Function which returns a React Element to display on the left side of the header. You can use it to implement your custom left button, for example:
```js
(
{
// Do something
}}
/>
),
}}
/>
```
#### `headerRight`
Function which returns a React Element to display on the right side of the header.
#### `headerContent`
Content of the header placed at the bottom of the header.
#### `headerStyle`
Style object for the header. You can specify a custom background color here, for example.
#### `headerTitleStyle`
Styles for the title component.
#### `headerLeftContainerStyle`
Customize the style for the container of the `headerLeft` component, for example to add padding.
#### `headerRightContainerStyle`
Customize the style for the container of the `headerRight` component, for example to add padding.
#### `headerTitleContainerStyle`
Customize the style for the container of the `headerTitle` element.
#### `headerBackgroundContainerStyle`
Customize the style for the container of the `headerBackground` element.
#### `headerTintColor`
Tint color for the header
#### `headerTransparent`
Defaults to `false`. If `true`, the header will not have a background unless you explicitly provide it with `headerBackground`. The header will also float over the screen so that it overlaps the content underneath.
This is useful if you want to render a semi-transparent header or a blurred background.
Note that if you don't want your content to appear under the header, you need to manually add a top margin to your content. React Navigation won't do it automatically.
#### `headerBackground`
Function which returns a React Element to render as the background of the header. This is useful for using backgrounds such as an image or a gradient.
For example, you can use this with `headerTransparent` to render a blur view to create a translucent header.
#### `headerShown`
Whether to show or hide the header for the screen. The header is shown by default. Setting this to `false` hides the header.
## Group
`Group` components are used to group several screens inside a navigator.
A `Group` is returned from a createStackNavigator function:
```jsx
const Stack = createStackNavigator(); // Stack contains Screen & `Navigator` properties
```
After creating the navigator, it can be used as children of the Navigator component:
```jsx
```
It's also possible to nest `Group` components inside other `Group` components.
## Props
### screenOptions
Options to configure how the screens inside the group get presented in the navigator. It accepts either an object or a function returning an object:
```jsx
{/* screens */}
```
When you pass a function, it'll receive the route and navigation:
```jsx
({
title: route.params.title,
})}
>
{/* screens */}
```
These options are merged with the options specified in the individual screens, and the screen's options will take precedence over the group's options.
See Options for screens for more details and examples.
## navigationKey
Optional key for a group of screens screen. If the key changes, all existing screens in this group will be removed (if used in a stack navigator)
or reset (if used in a tab or drawer navigator):
```jsx
{/* screens */}
```
This is similar to the navigationKey prop on Screen, but applies to a group of screens.
---
id: elevation
category: Styling
title: elevation
description: Tool to create depth on screen for users
---
```jsx
import { elevation } from '@uhg-abyss/mobile';
```
## Properties
```typescript
elevation(level: number)
```
## Usage
The `elevation` function take in a single parameter that chooses the magnitude of the shadow effect
applied to the surface of the component. The parameter accepts integers 0 - 4 inclusive.
The function will return an object that can be placed in a component's style prop, which will add
the shadow effects directly to the component.
```jsx live
() => {
return (
Level 0
Level 1
Level 2
Level 3
Level 4
);
};
```
---
id: flatten-tokens
category: Theme
title: flattenTokens
description: Tool to combine tokens from multiple sources into a single object.
---
```jsx
import { flattenTokens } from '@uhg-abyss/mobile';
```
## Properties
```typescript
flattenTokens(...themes: TokenTheme[])
```
## Usage
The `flattenTokens` function is designed to flatten and merge tokens from multiple JSON structures,
to support a layered system where tokens from different themes can override core, semantic, and component
level tokens.
The Abyss theme accepts an object with the following keys to define the theme:
`sizing`, `spacing`, `color`, `borderRadius`, `borderWidth`, `boxShadow`, `fontFamilies`, `fontWeights`,
`fontSizes`, `lineHeights`, `letterSpacing`, `border`, and `opacity`.
This function will return a single object in this format that can be used to create a theme object via
[createTheme](/mobile/tools/create-theme) for later use in the [ThemeProvider](/mobile/ui/theme-provider).
## Overriding Abyss Token Theme
In this example, we use `flattenTokens` and `createTheme` to create a new theme object, which is then passed
into `ThemeProvider` to override the Abyss theme and customize the `Toast` component.
```jsx live
const coreTheme = {
core: {
color: {
brand: {
60: {
value: '#60A0F0',
type: 'color',
description: 'Overrides info toast with core token',
},
},
red: {
60: {
value: '#FF5757',
type: 'color',
description: 'Overrides error toast with core token',
},
},
},
},
};
const semanticTheme = {
semantic: {
color: {
surface: {
container: {
status: {
warning: {
saturated: {
value: '#FFAC63',
type: 'color',
description: 'Overrides warning toast with semantic token',
},
},
},
},
},
},
},
};
const componentTheme = {
toast: {
color: {
background: {
success: {
value: '#61D48F',
type: 'color',
description: 'Overrides success toast with component token',
},
error: {
value: '{core.color.red.60}',
type: 'color',
description: 'Overrides error toast with component token',
},
},
icon: {
leading: {
value: '{core.color.neutral.80}',
type: 'color',
description: 'Toast color icon leading',
},
close: {
value: '{core.color.neutral.80}',
type: 'color',
description: 'Toast color icon close',
},
},
text: {
heading: {
value: '{semantic.color.text.interactive.rest.tertiary}',
type: 'color',
description: 'Toast color heading',
},
link: {
value: '{semantic.color.text.interactive.rest.tertiary}',
type: 'color',
description: 'Toast color link',
},
notification: {
value: '{semantic.color.text.interactive.rest.tertiary}',
type: 'color',
description: 'Toast color notification',
},
},
},
'font-size': {
heading: {
value: '{core.font-size.lg}',
type: 'fontSizes',
description: 'Overrides toast heading font size with component token',
},
},
'line-height': {
value: '{core.line-height.lg}',
type: 'lineHeights',
description: 'Overrides toast line height with component token',
},
},
};
const Toasts = ({ overridden }) => {
return (
{overridden
? 'Info Toast color overridden by Core Theme'
: 'You can only compare up to 4 providers'}
{overridden
? 'Success Toast color overridden by Component Theme'
: 'Your estimate has been saved!'}
{overridden
? 'Warning Toast color overridden by Semantic Theme'
: 'Be careful what you wish for!'}
{overridden
? 'Error Toast color is overridden by Component & Core Theme'
: 'Your estimate did not save!'}
);
};
const flattenedTokens = flattenTokens(coreTheme, semanticTheme, componentTheme);
const theme = createTheme('uhc', { theme: flattenedTokens });
const styles = StyleSheet.create({
heading: {
marginLeft: '$md',
marginBottom: '$sm',
marginTop: '$lg',
},
});
render(() => {
return (
Original ThemeCustom Theme
);
});
```
---
id: styled
category: Styling
title: styled
description: Tool to style elements.
---
```jsx
import { styled } from '@uhg-abyss/mobile';
```
## Properties
```typescript
styled(
nativeElement: string | React.FC,
config?: object
)
```
## Object Syntax Only
Write using the JavaScript object style syntax. The reasons for this are: performance, bundle size, and developer experience.
```jsx
const Button = styled('Pressable', {
backgroundColor: '$interactive3',
borderColor: '$primary1',
borderWidth: 2,
borderRadius: 24,
padding: 12,
});
```
```jsx live
() => {
const Button = styled('Pressable', {
backgroundColor: '$interactive3',
borderColor: '$primary1',
borderWidth: 2,
borderRadius: 24,
padding: 16,
});
return ;
};
```
## Prop Interpolation vs Variants
You can conditionally apply variants at the consumption level.
```jsx
const Button = styled('Pressable', {
...
variants: {
isDisabled: {
true: { backgroundColor: '$gray2' },
},
},
});
```
```jsx live
() => {
const Button = styled('Pressable', {
alignItems: 'center',
borderRadius: 24,
paddingVertical: 8,
paddingHorizontal: 16,
backgroundColor: '$primary1',
variants: {
isDisabled: {
true: { backgroundColor: '$gray2' },
},
},
});
return (
);
};
```
## Tokens and Themes
You can define tokens in the config file and seamlessly consume and access directly in the Style Object.
See [Abyss Theme Tokens](/mobile/ui/theme-provider/#abyss-theme-tokens) to see the default tokens.
```jsx
const Button = styled('Pressable', {
...
backgroundColor: '$primary1',
paddingVertical: '$sm',
paddingHorizontal: '$md',
});
```
```jsx live
() => {
const Button = styled('Pressable', {
alignItems: 'center',
borderRadius: 24,
paddingVertical: '$sm',
paddingHorizontal: '$md',
backgroundColor: '$primary1',
});
return (
);
};
```
### Light and Dark Theme
```jsx
const Button = styled('Pressable', {
...
light: {
backgroundColor: '$white',
borderWidth: 2,
borderColor: '$primary1',
},
dark: { backgroundColor: '$primary1' },
});
```
### Landscape and Portrait Orientation
Use `landscape` and `portrait` to define styles specific to the device orientation.
```jsx
const OrientationView = styled('View', {
...
landscape: {
flexDirection: 'row',
paddingVertical: '$xs',
},
portrait: {
paddingVertical: '$sm',
},
});
```
## Animations
You can use Animated within a styled component to add animations. Animation values must be passed to the component's `style` prop, not placed within the styled configs.
```jsx
import { Animated } from 'react-native';
const AnimatedButton = styled(Animated.View, {
alignItems: 'center',
borderRadius: 24,
paddingVertical: '$sm',
paddingHorizontal: '$md',
backgroundColor: '$primary1',
});
const animatedValue = useRef(new Animated.Value(1)).current;
const fade = (direction) => {
Animated.timing(animatedValue, {
toValue: direction === 'in' ? 0.95 : 1,
duration: direction === 'in' ? 100 : 300,
useNativeDriver: true,
easing: Easing.bezier(0.25, 0.1, 0.25, 0.1),
}).start();
};
const handlePressIn = (e) => {
fade('in');
};
const handlePressOut = (e) => {
fade('out');
};
```
```jsx live
() => {
const ButtonWrapper = styled('Pressable', {});
const AnimatedButton = styled(Animated.View, {
alignItems: 'center',
borderRadius: 24,
paddingVertical: '$sm',
paddingHorizontal: '$md',
backgroundColor: '$primary1',
});
const animatedValue = useRef(new Animated.Value(1)).current;
const fade = (direction) => {
Animated.timing(animatedValue, {
toValue: direction === 'in' ? 0.95 : 1,
duration: direction === 'in' ? 100 : 300,
useNativeDriver: Platform.select({
native: true,
default: false,
}),
easing: Easing.bezier(0.25, 0.1, 0.25, 0.1),
}).start();
};
const handlePressIn = (e) => {
fade('in');
};
const handlePressOut = (e) => {
fade('out');
};
return (
Button
);
};
```
## Dynamic/Static
When static variants won't work and you need a variable style, you can use the `props` config in the `styled` tool. Place all of your styles along with variants in the static config. The `props` config takes in a function with the props passed into the component as the function's parameters. You can then use those props to handle dynamic styles like sizing and colors. The function should return the style properties to add to the component. The `props` function overrides static styles and styles defined in `variants`.
For the best results and performance, it is recommended to use variants when possible.
```jsx live
() => {
const Button = styled('Pressable', {
borderRadius: 24,
alignItems: 'center',
justifyContent: 'center',
variants: {
variant: {
solid: { backgroundColor: '#d9f6fa' },
outline: {
backgroundColor: '$white',
borderWidth: 2,
borderColor: '$primary1',
},
},
isDisabled: {
true: { backgroundColor: '$gray2', borderWidth: 0 },
},
},
props: ({ size }) => {
return { padding: size + 4 };
},
});
return (
);
};
```
---
id: tokenize
category: Theme
title: tokenize
description: Tool to tokenize props in a component.
---
```jsx
import { tokenize } from '@uhg-abyss/mobile';
```
## Properties
```typescript
tokenize(
component: React.Component,
tokenObj: object
): React.Component;
```
There are times when a component accepts a prop that could potentially map to an Abyss token.
For example, the React Native SVG Circle
component has a `fill` prop that accepts a color. We can use the `tokenize` function to allow the `fill` prop to now accept an Abyss color token.
```jsx
const TokenizedCirle = tokenize(Circle, { fill: 'colors' });
```
The default values that can be used for a prop are `'colors'`, `'space'`, `'fontSizes'`, `'lineHeights'`, `'fontWeights'`, `'fonts'` & `'radii'`.
The tokens that exist for each value are defined in the [ThemeProvider](/mobile/ui/theme-provider/#abyss-theme-tokens).
## Basic Example
The TouchableHighlight component has a prop, `underlayColor` that accepts a color.
Since we have tokens for colors, we can use the `tokenize` function to map the prop to accept tokens.
```jsx
const TokenizedTouchableHighlight = tokenize(TouchableHighlight, {
underlayColor: 'colors',
});
```
Now we can use a color token as a value for the `underlayColor` prop. Press the button below to see the underlay color.
```jsx live
const TokenizedTouchableHighlight = tokenize(TouchableHighlight, {
underlayColor: 'colors',
});
render(() => {
return (
{}}
accessibilityRole="button"
>
Press Me
);
});
```
### Advanced Example
If the prop that should accept tokens is an object, the token object can be mapped to an object.
For example, the `style` prop on a View accepts an object with many props that can be mapped to tokens.
```jsx
const TokenizedView = tokenize(View, {
style: {
backgroundColor: 'colors',
borderColor: 'colors',
marginLeft: 'space',
borderRadius: 'radii',
},
});
```
Now, those four props can now accept tokens.
```jsx live
const TokenizedView = tokenize(View, {
style: {
backgroundColor: 'colors',
borderColor: 'colors',
marginLeft: 'space',
borderRadius: 'radii',
},
});
render(() => {
return (
);
});
```
---
id: with-theme
category: Util
title: withTheme
description: Tool to wrap a component with a higher order component.
---
```jsx
import { withTheme } from '@uhg-abyss/mobile';
```
This function takes a component and returns a higher order component with the current theme passed into the child.
## Usage
`withTheme` has one argument: the component to be wrapped. This sample code will show the difference.
The first component will not have the theme passed to it, while the second will.
```jsx
() => {
const UnwrappedComponent = (props) => {
return {JSON.stringify(props, null, 4)};
};
const WrappedComponent = withTheme(UnwrappedComponent);
return (
Here are the props of a component not wrapped with the withTheme
function
Here are the props of a component that *are* wrapped with the withTheme
function
);
};
```
```jsx live
() => {
const UnwrappedComponent = (props) => {
return {JSON.stringify(props, null, 4)};
};
const WrappedComponent = withTheme(UnwrappedComponent);
return (
Here are the props of a component not wrapped with the withTheme
function
Here are the props of a component that *are* wrapped with the withTheme
function
);
};
```
---
id: accordion
category: Content
title: Accordion
description: A vertically stacked list of headers that reveal or hide associated sections of content.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/1Uml7LO8NTEWoBUAl4DTaG/Abyss-Mobile?node-id=10126-35246&t=2iqvkqjkI4KBEphM-0
---
```jsx
import { Accordion } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Accordion',
inputs: [
{
prop: 'type',
type: 'select',
options: [
{ label: 'single', value: 'single' },
{ label: 'multiple', value: 'multiple' },
],
},
{
prop: 'defaultValue',
type: 'select',
options: [
{ label: 'none', value: '' },
{ label: 'sandbox-1', value: 'sandbox-1' },
{ label: 'sandbox-2', value: 'sandbox-2' },
{ label: 'sandbox-3', value: 'sandbox-3' },
],
},
{
prop: 'isCollapsible',
type: 'boolean',
},
{
prop: 'isDisabled',
type: 'boolean',
},
]
}
SURPRISE - Sandbox Accordion 1
SURPRISE - Sandbox Accordion 2
SURPRISE - Sandbox Accordion 3
```
## Type Multiple
Use the `type` property to set the Accordion to either have `single` or `multiple` open items. The default is set to `single`.
```jsx live
SURPRISE - Sandbox Accordion 1
SURPRISE - Sandbox Accordion 2
SURPRISE - Sandbox Accordion 3
```
## Default Value - Single
Use the `defaultValue` property to set an initial Accordion to be open based on its `value` property. When type is set to `single` pass in a string.
```jsx live
SURPRISE - Sandbox Accordion 1
SURPRISE - Sandbox Accordion 2
SURPRISE - Sandbox Accordion 3
```
## Default Value - Multiple
When the `type` of the Accordion is set to `multiple` pass in a string array.
```jsx live
SURPRISE - Sandbox Accordion 1
SURPRISE - Sandbox Accordion 2
SURPRISE - Sandbox Accordion 3
```
## Collapsible
The `isCollapsible` property allows closing content when clicking the trigger for an open item. When `true` you are allowed to collapse all items. When `false` one item will always remain open. The default is set to `true`. Collapsible does not apply when the type is "multiple".
```jsx live
Accordion Content 1
Accordion Content 2
Accordion Content 1
Accordion Content Item 2
```
## Disabled
Use the `isDisabled` property to disable the entire `Accordion` or individual levels. The default is set to `false`.
```jsx live
Not disabled
Disabled
Not disabled
Disabled
Disabled
```
## Border Variants
Accordion borders can be manipulated using the below props:
`hideBorderTop` | hides the border at the top of the accordion.
`hideBorderBottom` | hides the border at the bottom of the accordion.
`hideBorderAll` | hides all borders in the accordion.
```jsx live
Hides the border at the top of the accordion
Hides the border at the top of the accordion
Hides the border at the bottom of the accordion
Hides the border at the bottom of the accordion
Hides all borders in the accordion
Hides all borders in the accordion
```
## onValueChange
The `onValueChange` property is an event handler that is called when the expanded state of any item changes.
```jsx live
() => {
return (
console.log('Multi Value', val)}
style={{ marginBottom: 20 }}
>
Accordion Content 1
Accordion Content 2
Accordion Content 3
console.log('Single Value', val)}
>
Accordion Content 1
Accordion Content 2
Accordion Content 3
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: accumulator-v2
category: Data Viz
title: V2Accumulator
description: A graphical representation of a data set based on one variable.
design: https://www.figma.com/design/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=60560-2884&t=nVava1vxhAz8Wrvz-0
subDirectory: Accumulator/v2
sourceIsTS: true
---
```jsx
import { V2Accumulator } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Accumulator',
inputs: [
{
prop: 'percentage',
type: 'number',
defaultValue: 50
},
{
prop: 'animationDelay',
type: 'number',
},
{
prop: 'color',
type: 'string',
defaultValue: '$conditional7',
},
]
}
```
## Percentage
The `percentage` prop determines how far the accumulator will move. The prop accepts numbers between `0` and `100`
The default is `0`.
```jsx live
```
## Animation Delay
The `animationDelay` prop is used to start the animation after a given delay (milliseconds).
The default is `0`.
```jsx live
() => {
const [animated, toggle] = useToggle(false);
const percentage = animated ? 40 : 0;
return (
);
};
```
## Color
The `color` prop is used to set the color for the accumulator track.
The default is set to `$conditional7`.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: accumulator
category: Data Viz
title: Accumulator
description: A graphical representation of a data set based on one variable.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=20095%3A102386
subDirectory: Accumulator/v1
---
```jsx
import { Accumulator } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Accumulator',
inputs: [
{
prop: 'percentage',
type: 'number',
defaultValue: 50
},
{
prop: 'animationDelay',
type: 'number',
},
]
}
```
## Percentage
The `percentage` prop determines how far the accumulator will move. The prop accepts numbers between `0` and `100`
The default is `0`.
```jsx live
```
## Animation Delay
The `animationDelay` prop is used to start the animation after a given delay (milliseconds).
The default is `0`.
```jsx live
() => {
const [animated, toggle] = useToggle(false);
const percentage = animated ? 40 : 0;
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: activity-tracker
category: Data
title: ActivityTracker
description: Displays a visual representation of the user's activity.
design: https://www.figma.com/design/wCMblLsq9TxAQvKzY3EfCt/UHC-Abyss-Mobile?node-id=56619-6859&t=7SRu2GmHzPNPQzaT-0
---
```jsx
import { ActivityTracker } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'ActivityTracker',
inputs: [
{
prop: 'title',
type: 'string',
},
{
prop: 'showActiveStep',
type: 'boolean',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'oneweek', value: 'oneweek' },
{ label: 'twoweeks', value: 'twoweeks' },
],
},
]
}
```
## Variants
Use the `variant` prop to determine the variant of the activity tracker. The `twoweeks` variant displays a 14-day option that does not contain an `showActiveStep`. The `oneweek` variant is the default.
```jsx live
```
## Completed Steps
Use the `completedSteps` prop to determine the steps that have been completed.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: alert
category: Feedback
title: Alert
description: Communicate a state that affects the entire system, not just a feature or page. It persists over a session and appears without the user initiating the action.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=10091%3A35499&t=KluMjh3mwaQrqcQh-0
---
```jsx
import { Alert } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Alert',
inputs: [
{
prop: 'title',
type: 'string',
},
{
prop: 'description',
type: 'string'
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'info', value: 'info' },
]
},
{
prop: 'isCloseable',
type: 'boolean'
},
]
}
Go To Results
```
## Title and Description
The `title` and `description` props are used to set the title and description of the alert.
Both props are required.
```jsx live
```
## isCloseable
The `isCloseable` prop determines if a close button is displayed in the alert. It defaults to `true` unless the `inline` prop is enabled.
```jsx live
```
## Variants
Use the `variant` property to set the color of the `Alert`.
The options are `success`, `warning`, `error`, and `info`. The default is `success`.
```jsx live
```
## Inline Variant
The inline variant functions the same as the default, but is rounder and takes up less width. It uses the `inline` prop, changing the border radius to create a more rounded look. The inline variant should be wrapped in a component that provides padding on the left and right (see example below).
```jsx live
() => {
const InlineWrapper = styled('View', {
paddingHorizontal: 48,
});
return (
);
};
```
## Children
Add Children to the Alert component by simply placing elements between the Alert tags. Children should be used for adding either a link or button.
Links and buttons can be added with the `Alert.Link` and `Alert.Button` components, respectively.
```jsx live
setIsVisible(false)}
>
}
>
Go To Results
}
>
Use current location
```
## Change Icon
Use the `icon` property to pass in a specific `Icon` component.
Since `title` and `description` are required props, icons are used in a setting in which it is just a decorative element (which is the default case for icons) and should be ignored by screen readers. The implementation below provides an example. Since the default of `isScreenReadable` is set to false, no specific changes need to be made for decorative icons. Find further guidance on material icons in the [Material Icons Tab](/mobile/ui/icon-material).
```jsx live
}
title="Search Title"
description="The icon is decorative because of text from the title and this description."
variant="info"
onClose={() => {}}
/>
```
## onClose
Use the `onClose` property to handle the action when close button is triggered. The `onClose` property is always required.
```jsx live
() => {
const [isVisible, toggleVisibility] = useToggle(true);
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: app-bar
category: Navigation
title: AppBar
description: Displays information and actions relating to the current screen.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=10091%3A35499&t=KluMjh3mwaQrqcQh-0
---
```jsx sandbox
{
component: 'AppBar',
inputs: [
{
prop: 'title',
type: 'string',
defaultValue: 'Title'
},
{
prop: 'truncateTitle',
type: 'boolean',
},
{
prop: 'titleAlignment',
type: 'select',
options: [
{ label: 'center', value: 'center' },
{ label: 'left', value: 'left' },
]
},
],
}
```
## Accessories
App Bar contains options to add several partner components, depending on the page the App Bar is designed for.
These accessories can be placed in the children of the AppBar.
- SearchBar
- A search input that allows users to search for content within your app.
- ProgressBar
- A complementary visual representation of the current step a user is on while
completing a form of inputs.
- Tabs
- A navigation tool for secondary pages and actions. When a page contains Tabs,
the user is able to horizontally scroll through the list of options.
- Segmented Controls
- A list of options, and there cannot be more than one segment selected, so under
the hood this behaves like a radio group.
- Avatar
- Used on the homepage App Bar, and within the nested actions for Selector Section
to show the current user on the app.
```jsx live
() => {
const [segmentTab, setSegmentTab] = useState('tab-1');
const [value, setValue] = useState('');
return (
{
return logger.log('Value submitted');
}}
colorScheme="dark"
placeholder="Search your benefits"
/>
For Michael
California
);
};
```
## Nested Content
Use the `AppBar.NestedContent` component to add nested content to the AppBar with the `nestedContent` prop.
The `AppBar.NestedContent` component adds padding and around the nested content and gaps between the nested content.
```jsx live
Nested ContentNested Content
}
right={
}
>
```
## Banner
Use the `Banner` prop to pass an accessory such as GlobalAppProcess to be displayed at the top of the AppBar.
- GlobalAppProcess
: Used to communicate system status or background processes.
```jsx live
}
/>
```
## Title Alignment
Use the `titleAlignment` props to configure the alignment of the title. The options can be either `center` or `left`
The default is `center`.
```jsx live
```
## Left and Right
The `left` and `right` props are used to placed content on the left and right sides of the title.
```jsx live
Cancel
}
right={1 of 5}
/>
```
## Variants
The App Bar’s functionality should change based on the page that it is on.
- Homepage - On the homepage, App Bar announces the user’s name, and shows
the Avatar of the specific user.
- Level 1 - Level One pages are reserved for the pages that are the highest
level of navigation. There is no previous content that navigated them to this page,
and to return to the homepage, the user will click on the Homepage tab on Tab Bar.
- Level 2 - Level Two pages are nested pages within a Level One page. The
Back button in the upper left corner of the title section will bring the user back
to the Level One page. Like the Level One page, these pages also host a number
of nested components used to help users navigate the page.
```jsx live
Homepage}
titleAlignment="left"
title="Home"
subtitle="Jessica Anderson"
right={
}
/>
Level 1
}
/>
Level 2
}
titleAlignment="center"
title="Home"
right={
}
/>
```
```jsx render
```
```jsx render
```
```jsx render
```
**It is the responsibility of consuming teams to make sure all components within AppBar are accessible.**
Dynamic Type
AppBar scales to 3XL. Additional Icons and Text passed to any prop of type node should
have `maxFontSizeMultiplier={1.3}` set.
```jsx render
```
---
id: arrow
category: Navigation
title: Arrow
description: Navigates between a set number of items.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=27809-47023&mode=design&t=txkb6WojbsllpkON-0
---
```jsx
import { Arrow } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Arrow',
inputs: [
{
prop: 'direction',
type: 'select',
options: [
{ label: 'back', value: 'back' },
{ label: 'forward', value: 'forward' },
]
},
]
}
```
## Direction
Use the `direction` prop to determine which way the arrow will face. The default is set to `'back'`.
```jsx live
```
## onPress
Use the `onPress` prop to determine the action when the arrow is pressed.
```jsx live
() => {
const [direction, setDirection] = useState('Press an arrow');
const handlePress = (d) => {
setDirection(d + ' pressed');
};
return (
handlePress('Back')} />
{direction} handlePress('Forward')} />
);
};
```
```jsx render
```
```jsx render
```
---
id: avatar
category: Data Display
title: Avatar
description: The Avatar component is used to represent a user, and displays the profile picture or the user initials as a fallback.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=10158%3A35251&t=0e2Zlqt54CaApzhj-0
---
```jsx
import { Avatar } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Avatar',
inputs: [
{
prop: 'initials',
type: 'string',
},
{
prop: 'size',
type: 'select',
options: [
{ label: 'large', value: 'large' },
{ label: 'Small', value: 'small' },
]
},
{
prop: 'colorTheme',
type: 'select',
options: [
{ label: 'blue', value: 1 },
{ label: 'green', value: 2 },
{ label: 'orange', value: 3 },
{ label: 'light blue', value: 4 },
]
},
{
prop: 'showBorder',
type: 'boolean'
},
]
}
```
## Images
Use the `imageUrl` prop to set the `Avatar` image. This can be used to create a co-branded avatar.
```jsx live
```
###### Co-branded Avatars
```jsx live
() => {
const AvatarBorder = styled('View', {
borderRadius: 100,
borderWidth: 4,
borderColor: '$interactive3',
marginLeft: -15,
});
return (
Abyss Design System
Home
);
};
```
## Color Theme
Use the `colorTheme` prop to set the color of the `Avatar`.
The options are `1` (blue), `2` (green), `3` (orange), and `4` (light blue). The default is `1` (blue).
```jsx live
```
## Size
Use the `size` prop to set the size of the `Avatar`.
The 2 options are `small`, `large`. The default is `small`.
```jsx live
```
## Notification
Use the Indicator component with the Avatar to display a notification. See [Indicator](/mobile/ui/indicator) for more details and examples.
```jsx live
```
## Show border
Use the `showBorder` prop to add a border to the Avatar.
```jsx live
```
```jsx render
```
```jsx render
```
## Dynamic Type
The avatar text will scale up to 3XL.
```jsx render
```
---
id: badge-v2
category: Data Display
title: V2Badge
description: Used to highlight an item's status for quick recognition.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9534%3A32348
subDirectory: Badge/v2
sourceIsTS: true
---
```jsx
import { V2Badge } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Badge',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'info', value: 'info' },
{ label: 'neutral', value: 'neutral' },
],
defaultValue: 'success',
},
{
prop: 'outline',
type: 'boolean',
},
]
}
Badge Sandbox
```
## Variants
Use the `variant` property to set the color of the `Badge`.
The options are `success`, `warning`, `error`, `info`, and `neutral`. The default is `success`.
```jsx live
Success BadgeWarning BadgeError BadgeInfo BadgeNeutral Badge
Success Badge
Warning Badge
Error Badge
Info Badge
Neutral Badge
```
## Outline
Use the `outline` property to turn on the outline of the `Badge`. The default is `false`.
```jsx live
Badge
Outlined Badge
```
## Icons
Use the `icon` property to set the icon of the `Badge`.
```jsx live
}
variant="success"
>
Complete
}
variant="error"
>
Incomplete
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: badge
category: Data Display
title: Badge
description: Used to highlight an item's status for quick recognition.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9534%3A32348
pagination_prev: null
---
```jsx
import { Badge } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Badge',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'info', value: 'info' },
{ label: 'neutral', value: 'neutral' },
]
},
{
prop: 'rounded',
type: 'boolean',
},
{
prop: 'outline',
type: 'boolean',
},
]
}
Badge Sandbox
```
## Variants
Use the `variant` property to set the color of the `Badge`.
The options are `success`, `warning`, `error`, `info`, and `neutral`. The default is `success`.
```jsx live
Success BadgeWarning BadgeError BadgeInfo BadgeNeutral Badge
Success Badge
Warning Badge
Error Badge
Info Badge
Neutral Badge
```
## Rounded
Use the `rounded` property to change the style of the `Badge` from rounded or squared. The default is `false`.
```jsx live
Squared Badge
Rounded Badge
```
## Outline
Use the `outline` property to turn on the outline of the `Badge`. The default is `false`.
```jsx live
Badge
Outlined Badge
```
## Icons
Use the `icon` property to set the icon of the `Badge`.
```jsx live
}
variant="success"
>
Complete
}
variant="error"
>
Incomplete
```
```jsx render
```
```jsx render
```
---
id: banner-v2
category: Layout
title: V2Banner
description: Used to provide high-level content in a heading, paragraph, and image format within a pressable for navigation.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG?node-id=1492-351&m=dev
subDirectory: Banner/v2
sourceIsTS: true
---
```jsx
import { V2Banner } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Banner',
inputs: [
{
prop: 'heading',
type: 'string',
defaultValue: '2 line heading max'
},
{
prop: 'paragraph',
type: 'string',
defaultValue: 'Description paragraph should not expand on more than four lines and truncates if that is the case.'
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'horizontal', value: 'horizontal' },
{ label: 'vertical-lg', value: 'vertical-lg' },
{ label: 'vertical-sm', value: 'vertical-sm' },
{ label: 'branded', value: 'branded' },
],
defaultValue: 'horizontal'
},
{
prop: 'background',
type: 'select',
options: [
{ label: 'White', value: 'white' },
{ label: 'Peach', value: 'peach' },
{ label: 'Mint', value: 'mint' },
{ label: 'Aqua', value: 'aqua' },
{ label: 'Sky Blue', value: 'sky-blue' },
],
defaultValue: 'white'
},
{
prop: 'isClosable',
type: 'boolean',
},
]
}
```
## Variants
Use the `variant` prop to set the type of `Banner` to render.
```jsx live
}
/>
```
## Background
Use the `background` prop to set the background color of the banner. The default value is `white`.
```jsx live
```
## Image
Use the `image` prop to set an image in the image container of the banner.
```jsx live
}
imageBackgroundColor="$pastel1"
/>
}
paragraph="Get 24/7 access to providers by phone, video, or tablet."
cta={
}
>
Visit Optum
}
/>
```
## Image Background Color
Use the `imageBackgroundColor` prop to set an image in the image container of the banner. The default is `$gray1`.
```jsx live
}
variant="horizontal"
/>
```
## CTA
Use the `cta` prop to set a call to action button in the banner. If a cta is set
the number of lines of the heading paragraph are limited depending on the size of the CTA.
To view the truncation rules, see the [Banner truncation conditions](https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG?node-id=1620-6985&m=dev).
```jsx live
}
imageBackgroundColor="$pastel1"
cta={
}
>
Button CTA
}
/>
}
variant="horizontal"
cta={
Link CTA
}
/>
```
```jsx render
```
```jsx render
```
## Dynamic Type
Text and icons scale to Abyss standards. Any images, illustrations, or IconBrand passed to Banner should not scale. Size AX5 and larger cause reordering and resizing of all variants.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: banner
category: Layout
title: Banner
description: Used to provide high-level content in a title, description, and image format within a pressable for navigation.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=18723-91680&mode=design&t=yH2CaS5OmhOCzV1a-0
subDirectory: Banner/v1
---
```jsx
import { Banner } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Banner',
inputs: [
{
prop: 'eyebrow',
type: 'string',
},
{
prop: 'title',
type: 'string',
defaultValue: 'Your Organizer'
},
{
prop: 'description',
type: 'string',
defaultValue: 'A "one-stop-shop" for the important things a caregiver could need to give you for providing the best care.'
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'horizontal-small', value: 'horizontal-small' },
{ label: 'horizontal-large', value: 'horizontal-large' },
{ label: 'vertical', value: 'vertical' },
{ label: 'branded', value: 'branded' },
]
},
{
prop: 'color',
type: 'select',
options: [
{label: '$white', value: '$white'},
{label: '$pastel1', value: '$pastel1'},
{label: '$pastel2', value: '$pastel2'},
{label: '$pastel3', value: '$pastel3'},
{label: '$pastel4', value: '$pastel4'},
],
},
{
prop: 'textSize',
type: 'select',
options: [
{label: 'small', value: 'small'},
{label: 'large', value: 'large'},
],
},
{
prop: 'grow',
type: 'boolean'
},
{
prop: 'fixed',
type: 'boolean'
},
{
prop: 'isDisabled',
type: 'boolean'
},
{
prop: 'showExternalIcon',
type: 'boolean'
},
{
prop: 'centerText',
type: 'boolean'
},
{
prop: 'isCloseable',
type: 'boolean'
},
]
}
```
## Variants
Use the `variant` prop to set the type of `Banner` to render.
The options are `horizontal-small`, `horizontal-large`, `vertical`, and `branded`.
Please note that some props will only work with certain variants. Be sure to follow design guidelines when deciding which variant to use for your content.
For variants to be used within Carousel use the [Carousel Banner](/mobile/ui/banner/#carousel-banner) component, while Featured Content Cards should use Banner.
```jsx live
}
/>
```
### isCloseable and isVisible
Use the `isCloseable` prop to add a close button to the banner. The default value is `false`. This flag works on horizontal small, horizontal large, and vertical variants.
When the button is pressed, the `onClose` callback is fired.
`isVisible` is a boolean prop that determines whether the banner is visible or not. The default value is `true`.
```jsx live
() => {
const [isVisible, setIsVisible] = React.useState(true);
const [isVisible2, setIsVisible2] = React.useState(true);
const [isVisible3, setIsVisible3] = React.useState(true);
return (
setIsVisible(false)}
/>
setIsVisible2(false)}
/>
setIsVisible3(false)}
/>
);
};
```
## Carousel Banner
Use the `Carousel.Banner` component for use within a carousel. The Carousel Banner receives the same props as Banner with the exception of the `textSize` and `grow` props. It does not allow for multiple variants within the same carousel. See [Carousel](/mobile/ui/carousel) for details on using the carousel component.
```jsx live
() => {
return (
,
]}
/>
,
]}
/>
,
]}
/>
}
/>,
]}
/>
);
};
```
## Text Content
There are three props that add to the text content area of the Banner: `eyebrow`, `title`, and `description`.
- eyebrow - Sets the eyebrow content above the`title` content. This can be
a string or a node.
- title - Sets the title content
- description - Sets the description content
```jsx live
Badge}
title={'Title Text'}
textSize={'small'}
/>
```
## Text Size
Use the `textSize` prop to set the size of the title and description text. By default it is set to `"large"`.
```jsx live
```
## Colors
Use the `color` prop to set the background color of the content container.
The options are the theme colors `$white`, `$pastel1`, `$pastel2`, `$pastel3`, and `$pastel4`.
The default is `$white`.
```jsx live
```
## Image
Use the `image` prop to set an image in the image container of the banner.
```jsx live
}
variant="horizontal-small"
/>
}
variant="branded"
href={'https://www.optum.com/'}
linkText="External Link"
/>
```
## Image Background Color
Use the `imageBackgroundColor` prop to set an image in the image container of the banner. The default is `$gray1`.
```jsx live
}
variant="horizontal-small"
/>
```
## Content
Use the `content` prop to add content to the container. When content is added and `fixed` is set to true, be sure to evaluate whether a title, eyebrow, or description is necessary as the fixed container may clip the additional content.
```jsx live
$0
cost
}
/>
$0
cost
}
/>
```
## Footer
Use the `footer` prop to add content to the bottom of the content container.
```jsx live
$0
cost
}
/>
```
## Link
Use the `linkText` prop to set the text of the link and the `href` prop to set the URL.
```jsx live
}
/>
}
/>
```
## CTA Type
The `ctaType` prop allows optional switching of the CTA element to either a Button or Link. The default CTA is a Link for non-branded variants, and a Button for the branded variant.
There are some Design guidelines regarding CTA use and truncation that are recommended, but not enforced by code. They can be found
[here.](https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/v1.58.0-App-Abyss-Global%E2%80%A8Component-Library?node-id=1492-351&t=lXSGUgv4HybmB0o2-0)
```jsx live
Defaults
}
/>
With Prop
}
/>
```
## Link Icon
Use the `linkIcon` prop to customize the icon displayed after the link text.
```jsx live
}
linkIcon={
}
/>
```
## Grow
Use the `grow` prop to stretch the horizontal banner variants to full width of its container. The default value is `false`.
```jsx live
```
## Fixed
Use the `fixed` prop to make the height of the banners static. When fixed is true, the `centerText` prop can be set to align the title and description content in the center.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
Text and icons scale to Abyss standards. Any images, illustrations, or IconBrand passed to Banner should not scale. Size AX5 and larger cause reordering and resizing of all variants.
---
id: bottom-sheet
category: Overlay
title: BottomSheet
description: A surface containing supplementary content that are anchored to the bottom of the screen.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=15431-86066&t=xQWp12dwBu1GhQOV-0
---
```jsx
import { BottomSheet } from '@uhg-abyss/mobile';
```
## Example
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
const [tempRadioValue, setTempRadioValue] = useState(radioValue);
const [isVisible, setIsVisible] = useState(false);
const [isVisible2, setIsVisible2] = useState(false);
const updateRadioValue = (save) => {
if (save) {
setRadioValue(tempRadioValue);
} else {
setTempRadioValue(radioValue);
}
setIsVisible(false);
};
return (
updateRadioValue()}
title="A really long title"
footer={
}
>
}
>
You can customize your estimate by deleting this step. Would you like
to delete this step from the estimate?
);
};
```
### Scrolling
When the content of the BottomSheet becomes too long to display, scrolling is automatically enabled. In code, the height of the content is compared to the max height of the BottomSheet, which is 90% of the screen.
To manually disable scrolling, setting `scrollEnabled` to `false` will switch the component from a ScrollView to a View. Default is `true,` meaning the
height of the content will determine scrollability.
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
const [tempRadioValue, setTempRadioValue] = useState(radioValue);
const [isVisible, setIsVisible] = useState(false);
const updateRadioValue = (save) => {
if (save) {
setRadioValue(tempRadioValue);
} else {
setTempRadioValue(radioValue);
}
setIsVisible(false);
};
return (
updateRadioValue()}
title="A really long title"
footer={
}
>
);
};
```
### Closing on Background Press
By default, the BottomSheet will close when the user taps on the background overlay. This can be disabled by setting the `disableOverlayPress` prop to `true`.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
title="Bottom Sheet with Background Click Disabled"
disableOverlayPress
footer={
}
>
Tapping outside this Bottom Sheet will not close it. Use the button
below to close.
);
};
```
## Advanced Layout
Layouts like BottomSheet and Modal can be used in combination with each other to create flows.
```jsx live
() => {
const team = [
{
firstName: 'Michael',
lastName: 'White',
linkText: 'California',
subText: 'MM/DD/YYYY',
value: '1',
},
{
firstName: 'Thomas',
lastName: 'Musengwa',
linkText: 'Arkansas',
subText: 'MM/DD/YYYY',
value: '2',
},
{
firstName: 'Bailey',
lastName: 'Surowiec',
linkText: 'Illinois',
subText: 'MM/DD/YYYY',
value: '3',
},
{
firstName: 'Pablo',
lastName: 'Zepeda',
linkText: 'California',
subText: 'MM/DD/YYYY',
value: '4',
},
];
const locations = [
{
name: 'Alabama',
value: 'AL',
},
{
name: 'Alaska',
value: 'AK',
},
{
name: 'Arizona',
value: 'AZ',
},
{
name: 'Arkansas',
value: 'AR',
},
{
name: 'California',
value: 'CA',
},
{
name: 'Colorado',
value: 'CO',
},
{
name: 'Connecticut',
value: 'CT',
},
{
name: 'Delaware',
value: 'DE',
},
{
name: 'Florida',
value: 'FL',
},
{
name: 'Georgia',
value: 'GA',
},
{
name: 'Hawaii',
value: 'HI',
},
{
name: 'Idaho',
value: 'ID',
},
{
name: 'Illinois',
value: 'IL',
},
{
name: 'Indiana',
value: 'IN',
},
{
name: 'Iowa',
value: 'IA',
},
{
name: 'Kansas',
value: 'KS',
},
{
name: 'Kentucky',
value: 'KY',
},
{
name: 'Louisiana',
value: 'LA',
},
{
name: 'Maine',
value: 'ME',
},
{
name: 'Maryland',
value: 'MD',
},
{
name: 'Massachusetts',
value: 'MA',
},
{
name: 'Michigan',
value: 'MI',
},
{
name: 'Minnesota',
value: 'MN',
},
{
name: 'Mississippi',
value: 'MS',
},
{
name: 'Missouri',
value: 'MO',
},
{
name: 'Montana',
value: 'MT',
},
{
name: 'Nebraska',
value: 'NE',
},
{
name: 'Nevada',
value: 'NV',
},
{
name: 'New Hampshire',
value: 'NH',
},
{
name: 'New Jersey',
value: 'NJ',
},
{
name: 'New Mexico',
value: 'NM',
},
{
name: 'New York',
value: 'NY',
},
{
name: 'North Carolina',
value: 'NC',
},
{
name: 'North Dakota',
value: 'ND',
},
{
name: 'Ohio',
value: 'OH',
},
{
name: 'Oklahoma',
value: 'OK',
},
{
name: 'Oregon',
value: 'OR',
},
{
name: 'Pennsylvania',
value: 'PA',
},
{
name: 'Rhode Island',
value: 'RI',
},
{
name: 'South Carolina',
value: 'SC',
},
{
name: 'South Dakota',
value: 'SD',
},
{
name: 'Tennessee',
value: 'TN',
},
{
name: 'Texas',
value: 'TX',
},
{
name: 'Utah',
value: 'UT',
},
{
name: 'Vermont',
value: 'VT',
},
{
name: 'Virginia',
value: 'VA',
},
{
name: 'Washington',
value: 'WA',
},
{
name: 'West Virginia',
value: 'WV',
},
{
name: 'Wisconsin',
value: 'WI',
},
{
name: 'Wyoming',
value: 'WY',
},
];
const [data, setData] = useState(team);
const [value, setValue] = useState(data[0].value);
const [member, setMember] = useState(data[0]);
const [isVisible, setIsVisible] = useState(false);
const [showModal, setShowModal] = useState(false);
const getCurrentMember = (data, val) => {
return data.find(({ value }) => value === val);
};
const getLocation = (locations, val) => {
return locations.find(({ value }) => value === val);
};
const showToastMessage = () => {
Toast.show({
text: 'Member changed',
variant: 'success',
});
};
const handlePress = () => {
setIsVisible(true);
};
const updateTeam = (newLocation) => {
const newArr = data.map((member) => {
if (member.value === value) {
member.linkText = newLocation;
}
return member;
});
setData(newArr);
};
const handlePressLink = (value) => {
const currentMember = getCurrentMember(data, value);
setValue(currentMember.value);
setShowModal(true);
};
const handleButtonPress = () => {
const currentMember = getCurrentMember(data, value);
setMember(currentMember);
setIsVisible(false);
showToastMessage();
};
const handleCellPress = (val) => {
const newLocation = getLocation(locations, val);
updateTeam(newLocation.name);
const currentMember = getCurrentMember(data, value);
Toast.show({
text:
currentMember.firstName +
"'s location updated to " +
newLocation.name +
'!',
variant: 'success',
});
};
const TextView = styled('View', {
justifyContent: 'center',
paddingLeft: 9,
});
const Content = styled('View', {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
backgroundColor: '$primary1',
padding: '$md',
});
return (
{'For ' + member.firstName}
{member.linkText}
setIsVisible(false)}
title={'Select a member'}
footer={}
>
{data.map(
({ linkText, value, firstName, lastName, subText }, i) => (
}
>
{subText && (
{subText}
)}
{linkText && (
handlePressLink(value)}
after={
}
>
{linkText}
)}
)
)}
setShowModal(false)}
actionLeft={
}
onActionLeftPress={() => {
setShowModal(false);
}}
>
{locations.map(({ value, name }) => (
handleCellPress(value)}
iconRight={
}
>
))}
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
## Focus Guidance
Abyss does not control the focus of components on the screen when the Bottomsheet is toggled off. To meet
accessibility guidelines, the focus must be set to the previous node when closed. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For example, if a button is pressed to open a Bottomsheet, focus must return to that button once it is closed, so that a screen reader or keyboard user may continue using the app where they left off.
```jsx render
```
---
id: box
category: Layout
title: Box
description: Used as a blanket filler to surround just about any component(s) with color or create a box of predefined size.
---
```jsx
import { Box } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Box',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'padding',
type: 'string',
},
{
prop: 'height',
type: 'string',
},
{
prop: 'width',
type: 'string',
},
{
prop: 'color',
type: 'string'
},
],
}
```
## Basic Usage
`Box` is a container component that can be used to organize or structure a screen. Use `height` and `width` to control the size.
## Children
`Box` takes children of type `node`.
```jsx live
() => {
return (
Abyss is cool!
);
};
```
## Color
The `color` prop sets the background color. The default is set to $gray2.
```jsx live
() => {
return (
);
};
```
## Padding
The `padding` prop sets the padding in all directions. The default is set to $md.
```jsx live
() => {
return (
Default PaddingLarge Padding
);
};
```
## Search Message Example
A simple component that displays a message with a link to search for a different term.
[Design](https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=64584-133368&mode=design&t=oXWMZJo7aLUqUiFG-0)
```jsx live
() => {
return (
Results for providers that can treat knee replacement in the following categories:
}>
Search for knee repladment instead
);
};
```
```jsx render
```
```jsx render
```
---
id: bullets
category: Controls
title: Bullets
description: Used to represent the active slide or card in a stack of slides, like a Carousel.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=12804-63325&t=NM5yYbHIHkde3zlc-0
---
```jsx
import { Bullets } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Bullets',
inputs: [
{
prop: 'bullets',
type: 'number',
},
],
}
() => {
const [active, setActive] = useState(1);
return (
)
}
```
## Usage
Bullets are the simplified visual pagination for the Carousel component. The active slide or card is shown with a long rectangle, while inactive slides are light blue circles. There will only ever be one active bullet at a time. When the user swipes the carousel or presses on an arrow, the animation of the bullet changes.
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [active, setActive] = useState(3);
return ;
};
```
## Bullets
Use the `bullets` prop to set the number of bullets. Bullets should not be used for less than three and no more than six cards, therefore this number should fall between three (3) and six (6).
```jsx live
() => {
const [active, setActive] = useState(1);
const [active2, setActive2] = useState(2);
return (
);
};
```
## Active
Use the `active` prop to set the position of the active bullet. This should be between 1 and the number of bullets. See the example below where the active bullet can be changed by pressing on a specific bullet, or by pressing on the numbered buttons, which directly set the active bullet.
```jsx live
() => {
const [active, setActive] = useState(1);
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: Button-V2
category: Navigation
title: V2Button
description: Used to trigger an action or event.
design: https://www.figma.com/design/wCMblLsq9TxAQvKzY3EfCt/v1.66.0-App-Abyss-UHC-Component-Library?node-id=9529-32359&p=f&m=dev
---
```jsx
import { V2Button } from '@uhg-abyss/mobile';
```
```jsx sandbox
{ component: 'V2Button',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'variant',
type: 'select',
defaultValue: 'brand',
options: [
{ label: 'brand', value: 'brand' },
{ label: 'neutral', value: 'neutral' },
{ label: 'destructive', value: 'destructive' },
{ label: 'inverse', value: 'inverse' },
],
},
{
prop: 'type',
type: 'select',
defaultValue: 'filled',
options: [
{ label: 'filled', value: 'filled' },
{ label: 'outline', value: 'outline' },
{ label: 'text', value: 'text' },
],
},
{
prop: 'size',
type: 'select',
defaultValue: 'large',
options: [
{ label: 'large', value: 'large' },
{ label: 'small', value: 'small' },
],
},
{
prop: 'isDisabled',
type: 'boolean',
},
],
}
Click Here!
```
## Button Types and Variants
V2Button provides distinct visual styles through separate `type` and `variant` props:
- Use the `type` prop to specify the button style category: `filled`, `outline`, or `text`.
- Use the `variant` prop to indicate purpose: `brand` (primary actions), `neutral` (secondary actions), `destructive` (dangerous actions), or `inverse` (on dark backgrounds).
By default, `brand` variant and `filled` type are enabled.
```jsx live
Filled Brand
Filled Neutral
Filled Destructive
Outline Brand
Outline Neutral
Outline Destructive
Text Brand
Text Neutral
Text Destructive
Filled Inverse
Outline Inverse
Text Inverse
```
## Size
Use the `size` prop to change the size of the button. The size prop can take in either `large` or `small`. The default value is `large`. To better visualize the difference, the Layout is preventing the large from taking up the full screen.
```jsx live
Large Button
Small Button
```
## Icon Position
The `iconPosition` prop controls where icons appear in your button. There are three options:
- `trailing` (default): Places the icon after the button text
- `leading`: Places the icon before the button text
- `iconOnly`: Creates a small circular button with only the icon and no text
```jsx live
Continue
Send Message
Back
Add to Cart
```
### Icon-Only Buttons
`iconPosition="iconOnly"` creates button with no text.
```jsx live
```
## Icons
V2Button provides icon support through the `icon` prop. You can display icons in different ways:
**Using an Icon Object:** Provide an icon object with properties:
- `name`: The icon name (from [IconSymbol](mobile/ui/icon-symbol))
- `variant`: icon style ('filled' or 'outlined')
**Using a String Name:** Provide the icon name as a valid IconSymbol name string.
**Using a React Node:** For advanced use cases, you can provide a custom Icon component.
**Using a Function:** Use a function that returns a React node, which receives the button's pressed state and allows `V2Button` to set the color according to Abyss color mappings, or override them.
```jsx live
Object
String
}
>
ReactNode
{
return (
);
}}
iconPosition="leading"
variant="destructive"
type="outline"
>
Function
```
## Loading
When `isLoading` is set to `true`, a spinner indicates that an action is in progress, and `onPress` events are disabled.
```jsx live
Button
Button
Button
Button
```
## Disabled
Use the `isDisabled` prop to render the button in a non-interactive state. A disabled button cannot be in a loading state.
```jsx live
Disabled Button
Cannot Delete
Unavailable
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: button
category: Navigation
title: Button
description: Used to trigger an action or event.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=8866%3A42214
---
```jsx
import { Button } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Button',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'variant',
type: 'select',
defaultValue: 'primary',
options: [
{ label: 'primary', value: 'primary' },
{ label: 'secondary', value: 'secondary' },
{ label: 'tertiary', value: 'tertiary' },
{ label: 'destructive', value: 'destructive' },
{ label: 'alt', value: 'alt' },
],
},
{
prop: 'size',
type: 'select',
defaultValue: 'large',
options: [
{ label: 'large', value: 'large' },
{ label: 'small', value: 'small' },
],
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'rounded',
type: 'boolean'
},
],
}
```
## Size
Use the `size` prop to change the size of the button. The size prop can take in either `large` or `small`. The default value `large`.
The large button fill the entire width of its container. The small button fits the content contained in the button.
```jsx live
```
## Variant
Use the `variant` prop to change the visual style of the Button. You can set the value to `primary`, `secondary`, `tertiary`, `destructive` or `alt`.
Primary buttons should only appear once per screen (not including the application header, modal dialog, or side panel). The default value is `primary`.
```jsx live
```
### Tertiary Variant
The tertiary variant now has different padding than other styles. The `large` size has a vertical padding of 6px and the `small` size has a vertical padding of 5px.
Users who wish to keep the previous gap between buttons will need to update the margin to 16px.
## Rounded
Use the `rounded` prop to make a rounded button. You can insert an icon as a child of the button.
```jsx live
```
## Disabled
Use the `isDisabled` prop to disable a button.
```jsx live
}
after={
}
>
Button
}
after={
}
>
Button
```
## Inserting Elements
Insert elements into the Button component using the `before` and `after` props.
```jsx live
}
>
Previous
}>
Next
```
## Preferred Icons
Here is a list of preferred icons accepted for use on buttons. If there’s one not listed, please use sparingly.
```jsx live
```
## Grouping Buttons
Pairing similar action buttons together, like “Previous” and “Next”, should use one Primary button and one secondary button, showing the expected action as the primary CTA.
```jsx live
}
>
Previous
}>
Next
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: calendar
category: Controls
title: Calendar
description: A control element that displays a full calendar month at one time.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=39874-170177&mode=design&t=Ridf1HoSvYi7LIPY-0
---
```jsx sandbox
{
component: 'Calendar',
}
() => {
const [value, setValue] = useState(new Date());
return (
)
}
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [value, setValue] = useState();
return ;
};
```
## Minimum and Maximum Date
Use the `minimumDate` and `maximumDate` props to set the min and max dates in the Calendar. The default values will be a 1 year range from the prop `value.`
```jsx live
() => {
const [value, setValue] = useState();
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
return (
);
};
```
## Excluded Dates
To exclude dates use the `excludeDate` prop. Set a function that receives date as an argument and returns true if date should be disabled. For example, to disable weekends, check if the day is 0 or 6.
```jsx live
() => {
const [value, setValue] = useState();
return (
{
return date.getDay() === 0 || date.getDay() === 6;
}}
/>
);
};
```
## Goals
Use the `goals` prop to add rewards to certain days on the calendar.
The goals prop must be an array of 'Goal' objects. A goal object has three properties
- `date`: The date the reward will be. Must be a date instance.
- `state`: The current state of the reward. Valid values are `'progress'` and `'complete'`.
- `percentage`: If the state of the goal is `'progress'`, you can add the completed percentage. Defaults to `50`.
```jsx live
() => {
const [value, setValue] = useState();
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
Calendar scales to 3XL. Star icon does not grow.
The date picker component in Abyss library is currently not accessible to users relying on screen readers and therefore it is hidden from screen reader users.
Please use the date input method as an alternative to the date picker.
```jsx render
```
---
id: card
category: Content
title: Card
description: A single or multi-section container used to display content related to a single subject.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/Sk3MrHYxjT39TKDzDU5LBc/Abyss-Mobile?node-id=12334%3A61355
---
```jsx
import { Card } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Card',
inputs: [
{
prop: 'children',
type: 'string',
},
]
}
Card Sandbox
```
## Basic usage
The Card component is a versatile wrapper used to display content related to a single subject.
One example of `Card` can be seen in [HomeWidget](/mobile/ui/home-widget).
```jsx live
Heading text exampleText example
```
## Pressable and Animations
The Card component extends the props of [Pressable](https://reactnative.dev/docs/pressable#props) and can be used as a button.
Use the `isDisabled` prop to disable the pressable responder. In the case where you place something with its own touch responder within the card, like a ScrollView, FlatList, SectionList, etc., you will want to disable the pressable responder.
[Animations](https://reactnative.dev/docs/animated#props) can be added via the `styles` prop targeting `abyss-card-root`.
A Card that is programmed as a button with a Call To Action (CTA) must use accessibility props like those in `Button`. This ensures assistive technology can reach, understand, and activate the card.
When building a CTA Card, text content should be short. A Screen Reader will present button content in one full string that cannot be navigated easily by the device. Large CTA Card text will be difficult for screen reader users to understand.
```jsx live
() => {
const scale = useRef(new Animated.Value(1)).current;
const shrink = () => {
Animated.timing(scale, {
toValue: 0.95,
duration: 300,
easing: Easing.linear,
useNativeDriver: true,
}).start();
};
const grow = () => {
Animated.timing(scale, {
toValue: 1,
duration: 300,
easing: Easing.linear,
useNativeDriver: true,
}).start();
};
return (
console.log('pressed')}
onPressIn={shrink}
onPressOut={grow}
accessible={true}
role="button"
styles={{
'abyss-card-root': {
paddingTop: 20,
height: 200,
alignItems: 'center',
transform: [{ scale }],
},
}}
>
Pressable CardPress card to log a console message
);
};
```
## Card.Section
The `Card.Section` subcomponent provides a card 16px of padding. A use case example is provided in [CheckBoxGroup](/mobile/ui/checkbox-group/#group-with-card).
```jsx live
Card Section
```
## Multi Select Card
A Card can be used as a container for selections by combining it with the [CheckboxGroup](/mobile/ui/checkbox-group) or [Checkbox](/mobile/ui/checkbox) components.
```jsx live
() => {
const form = useForm();
return (
Select All Claims (4)$278.89Dr. Sharon Tang$93.22Date of Service 5/11/23
Claim Information
Walgreens #927956$127.93Date of Service 5/5/23
Claim Information
Dr. Edward M Jenner$25.00Date of Service 10/30/22
Claim Information
Odin Medical Group$32.74Date of Service 12/9/22
Claim Information
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: carousel-v2
category: Content
title: V2Carousel
description: A circular conveyor of information, cycling between cards.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=12446-61354
---
** Disclaimer: ** On a mobile device the carousel has the full functionality of scrolling, pagination, and snapping to a slide. While on the web, the carousel is restricted to scrolling only by dragging the bottom scroll bar or using the pagination buttons.
```jsx
import { V2Carousel } from '@uhg-abyss/mobile';
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const colors = ['$pastel1', '$pastel2', '$pastel3', '$pastel4'];
return (
{
return (
Slide {index + 1}
);
}}
/>
);
};
```
## Disable Scrolling
Use the `disableScrolling` prop to prevent the carousel from scrolling.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [disableScrolling, toggleScrolling] = useToggle(true);
const colors = ['$pastel1', '$pastel2', '$pastel3', '$pastel4'];
return (
{
return (
Slide {index + 1}
);
}}
/>
);
};
```
## Disable Pagination
Use the `disablePagination` prop to remove the pagination bullets below the V2carousel.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [disablePagination, togglePagination] = useToggle(true);
const colors = ['$pastel1', '$pastel2', '$pastel3', '$pastel4'];
return (
{
return (
Slide {index + 1}
);
}}
/>
);
};
```
## Slide Gap
Use the `slideGap` prop to add a gap between each slide. The default value is `$carousel.space.slide-gap || 8`.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [currentSlide2, setCurrentSlide2] = useState(1);
const [disableScrolling, toggleScrolling] = useToggle();
const colors = ['$pastel1', '$pastel2', '$pastel3', '$pastel4'];
return (
{
return (
Slide {index + 1}
);
}}
/>
{
return (
Slide {index + 1}
);
}}
/>
);
};
```
## Snap Percentage
Use the `snapPercentage` prop to set minimum percent in either direction a carousel should be shifted to snap to another V2carousel.
The default value is `30`.
In the examples below, there is a green line denoting how much the carousel would need to scroll before snapping to the next slide.
```jsx live
() => {
const [currentSlides, setCurrentSlides] = useState([1, 1, 1]);
const snapPercents = [30, 50, 75];
const carousels = snapPercents.map((percent, i) => {
const changeSlide = (goToSlide) => {
setCurrentSlides((currentSlides) => {
const copySlides = currentSlides.slice(0);
copySlides[i] = goToSlide;
return copySlides;
});
};
const slideContent = ['Slide 1', 'Slide 2'];
return (
{
return (
{slideContent[index]}
);
}}
/>
Snap Percentage: {percent}
);
});
return {carousels};
};
```
## Data
Carousel is made to be used in conjunction with slides, therefore the `data` prop is required.
```
const slides = [
{
color: 'white',
eyebrow: 'New Service',
heading: 'Virtual Care',
paragraph:
'Get medical advice from the comfort of your home. Discover our new virtual care services.',
},
{
color: 'peach',
eyebrow: 'Mental health',
paragraph:
'Learn more about available mental health benefits and resources available to you',
heading: 'Explore Coverage & Support',
},
{
color: 'mint',
eyebrow: 'Update',
heading: 'COVID-19 Vaccine Information',
paragraph:
'Stay informed about the COVID-19 vaccine. Learn about eligibility, safety, and how to get your shot.',
},
{
color: 'aqua',
eyebrow: 'Event',
heading: 'United Healthcare Community Health Fair',
paragraph:
'Join us for a day of free health screenings and wellness activities. Bring your family and friends!',
},
{
color: 'sky-blue',
eyebrow: 'In-App Care',
heading: 'Real-time, online visits',
paragraph: 'Connect with a designated provider using your smartphone.',
},
];
```
## Render Slide
Use the `renderSlide` prop to render the data passed into V2Carousel. This function takes in the slide object and index number.
```
renderSlide={{({ slide, index }) => {
return (
{
console.log(`card ${index + 1} pressed`);
}}
/>);
}}}
```
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const slides = [
{
color: 'white',
eyebrow: 'New Service',
heading: 'Virtual Care',
paragraph:
'Get medical advice from the comfort of your home. Discover our new virtual care services.',
},
{
color: 'peach',
eyebrow: 'Mental health',
paragraph:
'Learn more about available mental health benefits and resources available to you',
heading: 'Explore Coverage & Support',
},
{
color: 'mint',
eyebrow: 'Update',
heading: 'COVID-19 Vaccine Information',
paragraph:
'Stay informed about the COVID-19 vaccine. Learn about eligibility, safety, and how to get your shot.',
},
{
color: 'aqua',
eyebrow: 'Event',
heading: 'United Healthcare Community Health Fair',
paragraph:
'Join us for a day of free health screenings and wellness activities. Bring your family and friends!',
},
{
color: 'sky-blue',
eyebrow: 'In-App Care',
heading: 'Real-time, online visits',
paragraph: 'Connect with a designated provider using your smartphone.',
},
];
return (
{
return (
{
console.log(`Card ${index + 1} pressed`);
}}
/>
);
}}
/>
);
};
```
### Carousel Card
Use the `V2Carousel.Card` component to display content on a card with pre-defined styled specific for use within a V2carousel. Please follow design guidelines when implementing.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [variant, setVariant] = useState('horizontal');
const optumBrand = (
);
const slides = [
{
color: '$white',
eyebrow: 'New Service',
heading: 'Virtual Care',
paragraph:
'Get medical advice from the comfort of your home. Discover our new virtual care services.',
},
{
color: '$pastel1',
eyebrow: 'Mental health',
paragraph:
'Learn more about available mental health benefits and resources available to you',
heading: 'Explore Coverage & Support',
},
{
color: '$pastel2',
eyebrow: 'Update',
heading: 'COVID-19 Vaccine Information',
paragraph:
'Stay informed about the COVID-19 vaccine. Learn about eligibility, safety, and how to get your shot.',
},
{
color: '$pastel3',
eyebrow: 'Event',
heading: 'United Healthcare Community Health Fair',
paragraph:
'Join us for a day of free health screenings and wellness activities. Bring your family and friends!',
},
{
color: '$pastel4',
eyebrow: 'Virtual Care',
heading: 'Real-time, online visits',
paragraph: 'Connect with a designated provider using your smartphone.',
},
];
return (
<>
{
return (
{
console.log(`Card ${index + 1} pressed`);
}}
/>
);
}}
/>
>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: carousel
category: Content
title: Carousel
description: A circular conveyor of information, cycling between cards.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=12446-61354
---
```jsx
import { Carousel } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Carousel',
inputs: [
{
prop: 'title',
type: 'string'
},
{
prop: 'disableScrolling',
type: 'boolean'
},
{
prop: 'disablePagination',
type: 'boolean'
},
{
prop: 'actionText',
type: 'string'
},
]
}
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const length = 5
const banners = Array.from({length}).map((_,i) => {
return Slide {i +1}
})
return (
)
}
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const length = 5;
const banners = Array.from({ length }).map((_, i) => {
return (
Slide {i + 1}
);
});
return (
);
};
```
## Disable Scrolling
Use the `disableScrolling` prop to prevent the carousel from scrolling.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [disableScrolling, toggleScrolling] = useToggle(true);
const length = 5;
const banners = Array.from({ length }).map((_, i) => {
return (
Slide {i + 1}
);
});
return (
);
};
```
## Disable Pagination
Use the `disablePagination` prop to remove the pagination bullets below the carousel.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [disablePagination, togglePagination] = useToggle(true);
const length = 5;
const banners = Array.from({ length }).map((_, i) => {
return (
Slide {i + 1}
);
});
return (
);
};
```
## Slide Gap
Use the `slideGap` prop to add a gap between each slide. The default value is `$sm || 8`.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [currentSlide2, setCurrentSlide2] = useState(1);
const [disableScrolling, toggleScrolling] = useToggle();
const length = 5;
const banners = Array.from({ length }).map((_, i) => {
return (
Slide {i + 1}
);
});
return (
);
};
```
## Snap Percentage
Use the `snapPercentage` prop to set minimum percent in either direction a carousel should be shifted to snap to another carousel.
The default value is `30`.
In the examples below, there is a green line denoting how much the carousel would need to scroll before snapping to the next slide.
```jsx live
() => {
const [currentSlides, setCurrentSlides] = useState([1, 1, 1]);
const snapPercents = [30, 50, 75];
const carousels = snapPercents.map((percent, i) => {
const changeSlide = (goToSlide) => {
setCurrentSlides((currentSlides) => {
const copySlides = currentSlides.slice(0);
copySlides[i] = goToSlide;
return copySlides;
});
};
const slides = [
Slide 1,
Slide 2,
];
return (
Snap Percentage: {percent}
);
});
return {carousels};
};
```
## Slides
Carousel is made to be used in conjunction with slides, therefore the `slides` prop is required. If you are not using the [Carousel Banner](/mobile/ui/banner#carousel-banner) component for slides, please be sure to make them accessible by passing in the current slide index along with the total slide count to the accessibility label.
### Carousel Banner
Use the `Carousel.Banner` component to display content on a banner with pre-defined styled specific for use within a carousel. The Carousel Banner receives the same props as [Banner](/mobile/ui/banner) with the exception of the `textSize` and `grow` props. It does not allow for multiple variants within the same carousel. Please follow design guidelines when implementing.
```jsx live
() => {
const [currentSlide, setCurrentSlide] = useState(1);
const [variant, setVariant] = useState('horizontal-small');
const optumBrand = (
);
return (
<>
{
return (
);
}
)}
currentSlide={currentSlide}
onSlideChange={setCurrentSlide}
snapPercentage={30}
/>
>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
Note that the `textSize` and `grow` props will not apply to the `Carousel.Banner` component.
```jsx render
```
---
id: cell-v2
category: Data Display
title: V2Cell
description: Typically used as a navigation element to display a page of categorized content.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/v1.66.0-App-Abyss-Global%E2%80%A8Component-Library?node-id=1242-1385&p=f&t=sMgU6UgXCqKGqjZe-0
sourceIsTS: true
---
```jsx
import { V2Cell } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Cell',
inputs: [
{
prop: 'eyebrow',
type: 'string',
defaultValue: 'eyebrow'
},
{
prop: 'heading',
type: 'string',
defaultValue: 'Cell Heading'
},
{
prop: 'subheading',
type: 'string',
defaultValue: 'Subheading'
},
{
prop: 'paragraph',
type: 'string',
defaultValue: 'Paragraph content here'
},
{
prop: 'value',
type: 'string',
},
{
prop: 'indicator',
type: 'string',
},
]
}
```
## Leading Content
The `leadingContent` prop defines the cell's content on the left-hand side. This may contain the [IconBrand](/mobile/ui/icon-brand) component, a utility icon ([IconSymbol](/mobile/ui/icon-symbol)), or an [Avatar](/mobile/ui/avatar).
```jsx live
<>
}
/>
console.log('Cell Pressed')}
heading="Primary Care"
paragraph="Your first contact for to get care for your health."
leadingContent={}
/>
console.log('Cell Pressed')}
subheading="Search your benefits"
leadingContent={
}
/>
>
```
## Main Content
The `eyebrow` prop defines the cell's eyebrow. This prop can either be text or a custom component such as `Badge`.
The `heading` prop defines the cell's heading.
The `subheading` prop defines the cell's subheading.
The `paragraph` prop defines the cell's paragraph
The `trailingIcon` prop placed an icon at the end of the paragraph. This will not show unless there are also defined `paragraph` and `onPress` props. When this icon is present, only the icon is pressable, not the entire cell.
A [link](/mobile/ui/link) can be displayed below the paragraph using the `link` prop. A link may also be passed to the `value` prop to be displayed on the right side of the cell.
```jsx live
<>
console.log('Help Icon Pressed')}
trailingIcon={
}
/>
Badge}
onPress={() => console.log('Cell Pressed')}
/>
Go to Abyss
}
/>
>
```
## Trailing Content
The `value` prop defines the value component on the right side of the cell. This is generally used to display a numerical value but can also display the [Link](/mobile/ui/link) component.
If the `value` prop exists, the cell cannot contain an `onPress` function.
The `indicator` prop defines the indicator component on the right side of the cell. Unlike `value`, this prop can co-exist with an `onPress` function. Either a string or a custom Component can be passed here.
The `navIcon` prop defines the icon that appears on the far right side of the cell. This icon will only exist when an `onPress` function exists.
```jsx live
<>
Link Value
}
/>
console.log('Cell Pressed')}
heading="Cell heading"
paragraph="Cell with a string indicator and onPress"
indicator="Indicator"
/>
console.log('Cell Pressed')}
subheading="Badge Indicator"
indicator={
}
>
Badge
}
/>
console.log('Cell Pressed')}
navIcon={}
/>
>
```
## isDisabled
`isDisabled` is a prop available for type `radio`, `checkbox`, and `toggle`.
When `isDisabled` is present in [V2CellGroup](/mobile/ui/cell-group-v2), the entire group is disabled and cannot be modified. However, if `isDisabled` is present in `V2Cell`, only that cell is disabled and cannot be modified.
```jsx live
() => {
const [checkboxValue, setCheckboxValue] = useState([]);
const [radioValue, setRadioValue] = useState('one');
const [disableGroup, setDisableGroup] = useState(false);
const [disableCells, setDisableCells] = useState(false);
return (
<>
>
);
};
```
```jsx render
```
```jsx render
```
**It is the responsibility of consuming teams to make sure all components within Cell are accessible.** When possible, please test on physical devices for accessibility accuracy.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: cell-group-v2
category: Data Display
title: V2CellGroup
description: Cells present data in one or more vertically stacked rows.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/v1.66.0-App-Abyss-Global%E2%80%A8Component-Library?node-id=1242-1385&p=f&t=sMgU6UgXCqKGqjZe-0
sourceIsTS: true
---
```jsx
import { V2CellGroup } from '@uhg-abyss/mobile';
```
## Type Inheritance
When creating a `V2CellGroup` of type `radio`, `checkbox`, or `toggle`, it is important to use the `type` prop. Once a type prop is assigned to a CellGroup, every child will inherit the group's type and have access to all necessary providers preventing errors.
Below, you can see a few examples of type inheritance within `V2CellGroup`. Notice how `V2Cell` does not have the `type` prop, inheriting it from the CellGroup.
```jsx live
() => {
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [radioValue, setRadioValue] = useState('one');
const [value, setValue] = useState([]);
return (
<>
>
);
};
```
## Toggle Switch CellGroup
Cells of type `toggle` contain the content of the cell with a ToggleSwitch on the right side. Toggle Cells will return a boolean of the selected value onChange.
```jsx live
() => {
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [isToggleChecked2, setIsToggleChecked2] = useState(true);
return (
console.log('info button pressed')}
/>
);
};
```
## Radio Group
Cells of type `radio` are required to be wrapped in a `V2CellGroup` with type `radio`. Reference the [Type Inheritance](/mobile/ui/cell-group-v2/#type-inheritance) section above for more information.
Radio Cells contain the content of the cell with a radio button on the right side, and return the selected value onChange.
Radio `V2CellGroup` requires the `onChange` and `value` props.
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
return (
<>
Radio Group Example
>
);
};
```
## Checkbox Group
Cells of type `checkbox` are required to be wrapped in a `V2CellGroup` with type `checkbox`, reference the [Type Inheritance](/mobile/ui/cell-group-v2/#type-inheritance) section above for more information.
Checkbox Cells contain the content of the cell, with a checkbox on the right side.
Checkbox Cells works the same as a standard Checkbox Group, returning the selected cell values.
`selectAll` is a prop that can exist inside a Cell in a Checkbox CellGroup. This prop creates a select all checkbox that will select/deselect the entire checkbox list.
Checkbox `V2CellGroup`'s require the `onChange` and `value` props.
```jsx live
() => {
const [checkboxValue, setCheckboxValue] = useState([]);
return (
<>
Checkbox Group Example
>
);
};
```
## isDisabled
`isDisabled` is a prop available for type `radio`, `checkbox`, and `toggle`.
When `isDisabled` is present in `V2CellGroup`, the entire group is disabled and cannot be modified. However, if `isDisabled` is present in `V2Cell`, only that cell is disabled and cannot be modified.
```jsx live
() => {
const [checkboxValue, setCheckboxValue] = useState([]);
const [radioValue, setRadioValue] = useState('one');
const [disableGroup, setDisableGroup] = useState(false);
const [disableCells, setDisableCells] = useState(false);
return (
<>
>
);
};
```
```jsx render
```
**It is the responsibility of consuming teams to make sure all components within CellGroup are accessible.**
```jsx render
```
```jsx render
```
---
id: cell-group
category: Data Display
title: CellGroup
description: Present data in one or more vertically stacked rows.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9599%3A34319&t=OIAOmowjKZ4THvqh-0
---
```jsx
import { CellGroup } from '@uhg-abyss/mobile';
```
## Type Inheritance
When creating a `CellGroup` of type `radio`, `checkbox`, `toggle` or `dragAndDrop`, it is important to use the `type` prop. Once a type prop is assigned to a `CellGroup`, every child `CellGroup.Cell` will inherit the `CellGroups`'s type and have access to all necessary providers preventing errors.
Below, you can see a few examples of type inheritance within `CellGroup`. Notice how `CellGroup.Cell` does not have the `type` prop, causing `CellGroup.Cell` to inherit its type from `CellGroup`.
```jsx live
() => {
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [isToggleChecked2, setIsToggleChecked2] = useState(true);
const [radioValue, setRadioValue] = useState('one');
const [value, setValue] = useState([]);
return (
<>
>
);
};
```
## Cell Customization
The `icon` prop defines the cell's icon on the left-hand side. Either IconBrand or IconSymbol can be used here. When using IconBrand, you can customize the icon's background color using the `iconBackgroundColor` prop.
The `eyebrow` prop defines the cell's eyebrow. This prop can either be text or a custom component such as `Badge`.
The `title` prop defines the cell's title. The title's fontWeight can be modified via the `titleWeight`, `titleColor` and the `highlight` prop. The `highlight` prop will highlight the cell title to make it stand out. If your cell does not contain any `onPress` functionality, you can pass in the `onInfoButtonPress` prop, which will cause an info button to populate to the right side of the title.
The `subtitle` prop defines the cell's subtitle.
The `description` prop defines the cell's description
The `footer` prop defines the component that lives at the bottom of the cell's content section. This is generally used to add either a Link or a Badge.
The `value` prop defines the value component on the right side of the cell. If the `value` prop exists, the cell cannot contain an `onPress` function. Either a string or a custom component can be passed here. This is generally used to display a numerical value or a link.
The `indicator` prop defines the indicator component on the right side of the cell. Unlike `value`, this prop can co-exist with an `onPress` function. Either a string or a custom Component can be passed here.
The `pressIcon` prop defines the icon that appears on the far right side of the cell. This icon will only exist when an `onPress` function exists.
```jsx live
() => {
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [isToggleChecked2, setIsToggleChecked2] = useState(true);
const [radioValue, setRadioValue] = useState('one');
const [value, setValue] = useState([]);
return (
console.log('Cell Pressed')}
pressIcon={}
/>
console.log('Cell Pressed')}
eyebrow="CELL eyebrow"
title="Cell Title"
description="Cell description"
iconBackgroundColor="$pastel1"
titleWeight="$bold"
icon={
}
>
This is a badge console.log('Cell Pressed')}
eyebrow={Badge}
title="Cell Title"
subtitle="Cell subtitle"
description="Cell description"
titleWeight="$bold"
icon={
}
/>
}
footer={
Link
}
/>
console.log('Cell Pressed')}
title="Cell Title"
description="A segmented control is a linear set of two or more segments"
titleWeight="$bold"
icon={}
/>
console.log('Cell Pressed')}
title="Cell Title"
description="Cell description"
indicator="Indicator"
/>
console.log('Cell Pressed')}
title="Cell Title"
description="A segmented control is a linear set of two or more segments"
indicator={
}
>
Badge
}
/>
Link
}
/>
console.log('info button pressed')}
title="Cell Title"
/>
);
};
```
## Cell Header
For cells requiring a category title, use the `CellGroup.CellHeader` component within the `CellGroup`.
`CellHeader` has the following props:
- `title` - the title of the cell category.
- `value` - place content, such as a link, on the right side of the header cell.
- `onInfoButtonPress` - info button populates on the right side of the title.
```jsx live
() => {
const cellPressed = () => {
console.log('Cell Pressed');
};
return (
}
/>
}
/>
{
console.log('info button pressed');
}}
/>
}
/>
{
return console.log('See all pressed');
}}
>
See All
}
/>
}
/>
);
};
```
## Border Variants
Cell borders can be manipulated using the below props:
`hideBorderTop` | hides the border of the top cell.
`hideBorderBottom` | hides the border of the bottom cell.
`hideBorderAll` | hides the border of every cell.
`fullBorder` | makes border for every cell extend the full width of the parent.
```jsx live
() => {
return (
console.log('Cell Pressed')}
title="Hide Border Top"
/>
console.log('Cell Pressed')}
title="Hide Border Top"
/>
console.log('Cell Pressed')}
title="Hide Border Bottom"
/>
console.log('Cell Pressed')}
title="Hide Border Bottom"
/>
console.log('Cell Pressed')}
title="Hide Border All"
/>
console.log('Cell Pressed')}
title="Hide Border All"
/>
console.log('Cell Pressed')}
title="Border Full"
/>
console.log('Cell Pressed')}
title="Border Full"
/>
);
};
```
## Toggle Switch Cell
Cells of type `toggle` contain the content of the cell with a ToggleSwitch on the right side. Toggle Cells will return a boolean of the selected value onChange.
```jsx live
() => {
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [isToggleChecked2, setIsToggleChecked2] = useState(true);
return (
console.log('info button pressed')}
/>
);
};
```
## Radio Group
Cells of type `radio` are required to be wrapped in a `CellGroup` with type `radio`. Reference the `Type Inheritance` section above for more information.
Radio Cells contain the content of the cell with a radio button on the right side, and return the selected value onChange.
When using the type `radio` use the [Cell Header](/mobile/ui/cell-group/#cell-header) component for the group label.
Radio `CellGroup` requires the `onChange` and `value` props.
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
return (
);
};
```
## Checkbox Group
Cells of type `checkbox` are required to be wrapped in a `CellGroup` with type `checkbox`, reference the `Type Inheritance` section above for more information.
Checkbox Cells contain the content of the cell, with a checkbox on the right side.
Checkbox Cells works the same as a standard Checkbox Group, returning the selected cell values.
`selectAll` is a prop that can exist inside a Cell in a Checkbox CellGroup. This prop creates a select all checkbox that will select/deselect the entire checkbox list.
Checkbox `CellGroup`'s require the `onChange` and `value` props.
When using the type `checkbox` use the [Cell Header](/mobile/ui/cell-group/#cell-header) component for the group label.
```jsx live
() => {
const [checkboxValue, setCheckboxValue] = useState([]);
return (
);
};
```
## isDisabled
`isDisabled` is a prop available for type `radio` and `checkbox`.
When `isDisabled` is present in `CellGroup`, the entire group is disabled and cannot be modified. However, if `isDisabled` is present in `CellGroup.Cell`, only that cell is disabled and cannot be modified.
```jsx live
() => {
const [checkboxValue, setCheckboxValue] = useState([]);
const [radioValue, setRadioValue] = useState('one');
const [disableGroup, setDisableGroup] = useState(false);
const [disableCells, setDisableCells] = useState(false);
return (
);
};
```
## Custom Cells
Cells can be customized to fit design needs by passing it children and leaving the values empty for any combination of the `title`, `subtitle`, `description`, `eyebrow`, `icon`, and `linkText` properties.
```jsx live
() => {
return (
}
>
{'12/19/2022'}
}
>
Get Started
}
>
}
>
See the Designs
);
};
```
## CellCreator & DragAndDrop
This type of cell cannot be used inside a ScrollView.
`CellCreator` will create a new `DragAndDrop` Cell every time the blue plus is clicked.
`DragAndDrop` cells can be deleted via the red button on the left side, and dragged by clicking and holding the icon on the right side.
When the close button is pressed, the callback `onRemoveCell` will be called. The callback will contain the ID of the cell to be deleted.
When the add cell button is pressed, the callback `onAddCell` will be called. This function should create a new cell with a title and unique id.
Use the `data` prop to define the active cells. The `setData` prop is required for drag and drop functionality.
```jsx live
() => {
const keyRef = useRef(2);
const [childCells, setChildCells] = useState([
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' },
]);
const addCell = () => {
keyRef.current = keyRef.current + 1;
const newChildCell = {
text: `New Item ${keyRef.current}`,
id: keyRef.current,
};
setChildCells([...childCells, newChildCell]);
};
const removeItem = (id) => {
setChildCells(childCells.filter((item) => item.id !== id));
};
return (
removeItem(e)}
/>
{Object.keys(childCells).map((key) => (
ID: {childCells[key].id} | Text: {childCells[key].text}
))}
);
};
```
## Cell Group Examples
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
const [radioValue2, setRadioValue2] = useState('one');
const [isToggleChecked, setIsToggleChecked] = useState(false);
const [isToggleChecked2, setIsToggleChecked2] = useState(true);
const [checkboxValue, setCheckboxValue] = useState([]);
const [checkboxValue2, setCheckboxValue2] = useState([]);
const [checkboxValue3, setCheckboxValue3] = useState([]);
return (
<>
console.log('info button pressed')}
title="Cell Title"
/>
console.log('info button pressed')}
title="Cell Title"
pressIcon={}
/>
console.log('info button pressed')}
onPress={() => {
console.log('double');
}}
title="Cell Title"
/>
console.log('info button pressed')}
title="Cell Title"
/>
console.log('info button pressed')}
eyebrow="CELL eyebrow"
title="Cell Title"
description="A really long cell description that will wrap. A really long cell description that will wrap. A really long cell description that will wrap. A really long cell description that will wrap. A really long cell description that will wrap. A really long cell description that will wrap. A really long cell description that will wrap."
iconBackgroundColor="$pastel1"
titleWeight="$bold"
icon={
}
>
This is the badge console.log('info button pressed')}
eyebrow={Badge}
title="Cell Title"
subtitle="Cell subtitle"
description="Cell description"
titleWeight="$bold"
icon={
}
/>
console.log('info button pressed')}
title="Cell Title"
subtitle="Cell subtitle"
description="Cell description"
titleWeight="$bold"
icon={
}
/>
}
footer={
Link
}
/>
Badge}
title="Cell Title"
subtitle="Cell subtitle"
description="Cell description"
titleWeight="$bold"
iconBackgroundColor="$pastel1"
icon={
}
/>
console.log('info button pressed')}
title="Cell Title"
description="Cell description"
titleWeight="$bold"
titleColor="$primary1"
icon={}
/>
console.log('info button pressed')}
title="Cell Title"
description="Cell description"
icon={}
/>
console.log('info button pressed')}
title="Cell Title"
description="A really long cell description that will wrap A really long cell description that will wrap A really long cell description that will wrap A really long cell description that will wrap A really long cell description that will wrap A really long cell description that will wrap "
indicator="Indicator"
/>
console.log('info button pressed')}
title="Cell Title"
description="Cell description"
indicator={Indicator}
/>
console.log('info button pressed')}
title="Cell Title"
description="Cell description"
indicator={
}
>
Badge
}
/>
Link
}
/>
console.log('info button pressed')}
/>
}>
{'MM/DD/YYYY'}
}
>
{'Minneapolis, MN'}
>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
**It is the responsibility of consuming teams to make sure all components within CellGroup are accessible.**
---
id: checkbox
category: Forms
title: Checkbox
description: Used to mark an option as true/checked or false/not checked
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9602%3A34536
---
```jsx
import { Checkbox } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Checkbox',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'align',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'right', value: 'right' },
],
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isIndeterminate',
type: 'boolean',
},
]
}
() => {
const [isChecked, setChecked] = useState(true);
return (
);
};
```
## States
- Default - The default checkbox is unchecked.
- Checked - Use the `isChecked` prop to mark a checkbox as checked.
- Indeterminate - Use the `isIndeterminate` prop to set the checkbox as indeterminate.
- Disabled - Use the `isDisabled` prop to disable a checkbox. A disabled checkbox
is unusable and un-clickable.
- Help Text - Use the `helpText` prop to insert helpful text below the checkbox.
- Error Message - Use the `errorMessage` prop to display a custom error message
below the checkbox.
```jsx live
() => {
const form = useForm({
defaultValues: {
indeterminate: true,
'indeterminate-disabled': true,
'disabled-checked': true,
},
});
return (
);
};
```
## useForm (Recommended)
Using the `useForm` hook allows you to easily manage form state and validation.
```jsx live
() => {
const form = useForm();
const onSubmit = (data) => {
console.log('submitted', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [isChecked, setChecked] = useState(false);
return (
);
};
```
## Align
The `align` prop determines which side the checkbox is on. The options are `left` or `right`.
When the align prop is set to `right`, the label stays on the left and only the checkbox is set
to the rightmost edge of it's container. The default is `left`.
```jsx live
() => {
const form = useForm({
defaultValues: {
leftAlignedCheckbox: true,
rightAlignedCheckbox: true,
},
});
return (
);
};
```
```jsx render
```
```jsx render
```
## Dynamic Type
The checkbox icon scales up to 3XL, while any text passed in scales according to Abyss dynamic type standards.
```jsx render
```
---
id: checkbox-group
category: Forms
title: CheckboxGroup
description: Allows a user to select one or multiple items from a list.
---
```jsx
import { CheckboxGroup } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'CheckboxGroup',
inputs: [
{
prop: 'align',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'right', value: 'right' },
],
},
{
prop: 'isDisabled',
type: 'boolean',
},
]
}
() => {
const [value, setValue] = useState([]);
const handlePress = () => {
console.log(value);
};
return (
setValue(value)}>
);
};
```
## useForm (Recommended)
Using the `useForm` hook allows you to manage the state of the checkbox group more effectively, especially when dealing with forms.
```jsx live
() => {
const form = useForm({
defaultValues: {
'checkbox-form': ['two'],
},
});
const onSubmit = (data) => {
console.log('submitted', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [value, setValue] = useState(['two']);
return (
);
};
```
## Value
Checkboxes within a `CheckboxGroup` component require the `value` prop to be specified in order to function as part of the checkbox group.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Select All
Use the `CheckboxGroup.SelectAll` component to control the checked state for the entire group.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disabled
Use the `isDisabled` prop to disable the entire group.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Align
The `align` prop determines which side the checkbox is on for the entire group. The options are `left` or `right`.
When the align prop is set to `right`, the label stays on the left and only the checkbox is set
to the rightmost edge of it's container. The default is `left`.
```jsx live
() => {
const form = useForm();
const [align, setAlign] = useState(true);
return (
);
};
```
## Multi Select Card
A child component can be used instead of a traditional checkbox label. The `label` prop is removed and a component is added as a child of each checkbox.
See [Card](/mobile/ui/card/#Section) for more details on the Card used below.
```jsx live
() => {
const form = useForm();
return (
Select All Claims (4)$278.89Dr. Sharon Tang$93.22Date of Service 5/11/23
Claim Information
Walgreens #927956$127.93Date of Service 5/5/23
Claim Information
Dr. Edward M Jenner$25.00Date of Service 10/30/22
Claim Information
Odin Medical Group$32.74Date of Service 12/9/22
Claim Information
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: chip
category: Data Display
title: Chip
description: Chips are clickable, and used for filtering and selections.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=11953-60547&t=N5JdMpNlL65N19qO-0
---
```jsx
import { Chip } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Chip',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isClosable',
type: 'boolean',
},
{
prop: 'isTag',
type: 'boolean',
},
{
prop: 'isChecked',
type: 'boolean',
},
],
};
Chip;
```
## useState
Pass the value from the `useState` hook to the `isChecked` prop to set the checked state of the chip.
```jsx live
() => {
const [isChecked, setIsChecked] = useState(false);
return (
setIsChecked(!isChecked)}>
Chip
);
};
```
## Group
Group has three variants: `wrap`, `scroll` and `fit`. The `wrap` variant is the default.
### Wrap
Chips can be wrapped in a `Group`. When using this to group multiple chips together, a chip that is too long to stack horizontally wraps to the next line.
This variant allows any number of chips to be selected when each chip has an `isChecked` and `onChange`.
Alternatively, passing the state into the `Group` (and not individual chips) will allow only one chip to be selected at a time.
```jsx live
() => {
const [isChecked, setIsChecked] = useState(false);
const [isChecked2, setIsChecked2] = useState(false);
const [isChecked3, setIsChecked3] = useState(false);
const [isChecked4, setIsChecked4] = useState(false);
return (
setIsChecked(!isChecked)}>
Default Chip
setIsChecked2(!isChecked2)}>
A long time ago in a galaxy far, far away
setIsChecked3(!isChecked3)}
icon={
}
>
A long time ago in a galaxy far, far away
setIsChecked4(!isChecked4)}>
Chip
);
};
```
### Scroll
This variant has a filter button for selection and the chips scroll horizontally.
Only one chip can be selected in this group. The `title` prop is used to display a title on the bottom sheet.
```jsx live
() => {
const [val, setVal] = useState('one');
return (
Chip 1Chip 2Chip 3Chip 4Chip 5Chip 6
);
};
```
### Fit
This variant does not scroll or have a filter button. The chips will fit the width of the parent container.
Like the wrap variant, multiple chips can be selected when each chip has an `isChecked` and `onChange`, and only one chip can be selected when the state is passed into the `Group` (as shown).
```jsx live
() => {
const [val, setVal] = useState('one');
return (
Chip 1Chip 2Chip 3
);
};
```
## Icons
Use the `icon` prop to pass in a specific Icon component. Icons should be 20px and given an accurate title to meet accessibility standards. Find further guidance on material icons in the [Material Icons Tab](/mobile/ui/icon-material/).
```jsx live
() => {
const [isChecked, setIsChecked] = useState(false);
return (
setIsChecked(!isChecked)}
icon={
}
>
Chip
);
};
```
## Dismissible Chips
Use the `isClosable` prop with the `onClose` function to allow a chip to be dismissed. The checked and pressed states are not enabled with a dismissible chip.
```jsx live
() => {
const [shouldShow, setShouldShow] = useState(true);
return (
{shouldShow && (
setShouldShow(false)}>
Close Me
)}
);
};
```
## Disabled
Use the `isDisabled` prop to disable a chip.
```jsx live
}
isDisabled={true}
>
Disabled Chip
```
## Tag
Use the `isTag` prop to create a non-clickable chip.
```jsx live
Tag
```
## Width
Chips do not wrap if the text gets longer than the width of the parent container. Instead, the text will truncate.
```jsx live
() => {
const [isChecked, setIsChecked] = useState(false);
return (
setIsChecked(!isChecked)}
icon={
}
>
A long time ago in a galaxy far, far away
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: coachmark-v2
category: CTA
title: V2Coachmark
description: A temporal message that provides contextual information or help.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/branch/A6jVbwG9VlIxsupoiwvRjs/v1.72.0-App-Abyss-Global%E2%80%A8Component-Library?node-id=1360-50043&m=dev
subDirectory: Coachmark/v2
sourceIsTS: true
---
```jsx
import { V2Coachmark } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Coachmark',
inputs: [
{
prop: 'offset',
type: 'number',
},
{
prop: 'heading',
type: 'string',
},
{
prop: 'children',
type: 'string',
},
{
prop: 'position',
type: 'select',
options: [
{ label: 'Above', value: 'above' },
{ label: 'Below', value: 'below' },
],
},
{
prop: 'type',
type: 'select',
options: [
{ label: 'Dark', value: 'dark' },
{ label: 'Light', value: 'light' },
{ label: 'Light Border', value: 'light-border' },
],
default:'light-border'
},
{
prop: 'isVisible',
type: 'boolean',
},
{
prop: 'dismissible',
type: 'boolean',
},
]
}
Coachmark text
```
## Usage
Coachmarks always take the full width of the screen, should be placed with an 8px horizontal margin, and appear above or below the content it is pointing to. Content along the flat side should have a 16px margin from coachmark.
```jsx live
Coachmark text goes here, can be a 100 characters maximum and expands on no
more than four lines
```
#### Coachmark Tour
For creating guided tours with multiple sequential coachmarks, use the [CoachmarkTour](./CoachmarkTour.mdx) component. CoachmarkTour extends V2Coachmark functionality while providing:
- **Automatic step management**: Handles navigation between multiple coachmarks
- **Built-in controls**: Provides Previous/Next buttons and step counting
- **Coachmark positioning**: Calculates the best position and offset for each coachmark based on available screen space
- **Tour state management**: Manages the overall tour lifecycle (start, skip, complete)
Use V2Coachmark for standalone contextual help and CoachmarkTour for multi-step guided experiences.
## Position
Use the `position` prop to display the notch either above or below the coachmark. The default is `"above"`.
```jsx live
This coachmark appears above the content pointing down
Content
This coachmark appears below the content pointing up
```
## Type Variants
Use the `type` prop to change the visual appearance of the coachmark. Available options are `"dark"`, `"light"`, and `"light-border"`. The default is `"light-border"`.
```jsx live
Dark coachmark with white text
Light coachmark with dark text
Light coachmark with dark text and visible border
```
## Offset
Use the `offset` prop to change the horizontal position of the notch. It is determined as a percent from the left edge of the coachmark. The default is `50`.
```jsx live
() => {
const [offset, setOffset] = useState(0);
return (
The notch can be adjusted to point to specific content. 0 sets the notch
20px from the left and 100 sets the notch 20px from the right.
);
};
```
## Heading and Content
The V2Coachmark supports both a heading and body content. Use the `heading` prop for the title and pass the body content as `children`.
```jsx live
This is the body content that provides additional details about the feature
being highlighted.
```
## Footer Content
Use the `footer` prop to add custom footer content.
**Note:** For guided tours with multiple coachmarks, consider using the [CoachmarkTour component](./CoachmarkTour.mdx) which provides built-in navigation controls and step management.
```jsx live
() => {
const [currentStep, setCurrentStep] = useState(1);
const handleNext = () => {
setCurrentStep(currentStep + 1);
};
const handlePrev = () => {
setCurrentStep(currentStep - 1);
};
return (
handleNext()}
onPrevious={() => handlePrev()}
onComplete={() => setCurrentStep(1)}
/>
}
/>
Content Card 1Content Card 2 handleNext()}
onPrevious={() => handlePrev()}
onComplete={() => setCurrentStep(1)}
/>
}
>
{`This coachmark is inside Content Card and is currently on step ${currentStep}.`}
);
};
```
## Dismissible
Use the `dismissible` prop to control whether the close button is shown. Set to `false` to hide the close button for non-dismissible coachmarks.
```jsx live
<>
This coachmark cannot be dismissed by the user.
This coachmark can be dismissed by the user.
>
```
## onClose
Use the `onClose` prop to handle the action when the close button is pressed. Built into V2Coachmark is a fade out animation.
```jsx live
() => {
const [showCoachmark, setShowCoachmark] = useState(true);
const handleClose = () => {
setShowCoachmark(false);
console.log('Coachmark closed');
};
return (
Press the close button for coachmark to fade out.
setShowCoachmark(true)}
>
Show Coachmark
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: coachmark
category: CTA
title: Coachmark
description: A temporal message that provides contextual information or help.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=39456-18059&mode=design&t=FXPtfscG0ClF0Tf2-0
sourcePath: Coachmark/v1
---
```jsx
import { Coachmark } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Coachmark',
inputs: [
{
prop: 'offset',
type: 'number',
},
{
prop: 'children',
type: 'string',
},
{
prop: 'orientation',
type: 'select',
options: [
{ label: 'top', value: 'top' },
{ label: 'bottom', value: 'bottom' },
],
},
{
prop: 'colorScheme',
type: 'select',
options: [
{ label: 'Light', value: 'light' },
{ label: 'Dark', value: 'dark' },
],
},
{
prop: 'isVisible',
type: 'boolean',
},
{
prop: 'showBorder',
type: 'boolean',
},
]
}
Coachmark text
```
## Usage
Coachmarks always take the full width of the screen, should be placed with an 8px horizontal margin, and appear above or below the content it is pointing to. Content along the flat side should have a 16px margin from coachmark.
```jsx live
Coachmark text goes here, can be a 100 characters maximum and expands on no
more than four lines
```
## Orientation
Use the `orientation` prop to display the notch either on the top or bottom of the coachmark. The default is `"top"`.
```jsx live
Coachmark
Content below coachmark
```
## Offset
Use the `offset` prop to change the horizontal position of the notch. It is determined as a percent from the left edge of the coachmark. The default is `50`.
```jsx live
The notch should be center aligned with the element on the screen it refers
to. 0 sets the notch 20px from the left and 100 sets the notch 20px from the
right.
```
## onClose
Use the `onClose` prop to handle the action when the close button is pressed. Built into Coachmark is a fade out animation.
```jsx live
() => {
const [showCoachmark, setShowCoachmark] = useState(true);
const handleClose = () => {
setShowCoachmark(false);
console.log('Coachmark closed');
};
return (
Press the close button for coachmark to fade out. Any content below
coachmark should have a slide up animation to fill the remaining space.
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: coachmark-tour
category: CTA
title: CoachmarkTour
description: A guided tour system that displays contextual coachmarks to walk users through multiple steps of an interface.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/branch/A6jVbwG9VlIxsupoiwvRjs/v1.72.0-App-Abyss-Global%E2%80%A8Component-Library?node-id=1360-50043&m=dev
sourceIsTS: true
---
```jsx
import { CoachmarkTour } from '@abyss/mobile';
```
## Basic Usage
The CoachmarkTour system consists of two main components: `CoachmarkTour` (the provider) and `CoachmarkTour.Step` (wrapper for target elements). The tour displays V2Coachmarks in sequence to guide users through your interface.
**Important:** The `children` prop in `CoachmarkTour.Step` is different from `V2Coachmark`'s `children` prop. In `CoachmarkTour.Step`, the `children` prop contains the target element to highlight, while the coachmark content should be passed via the `description` prop. This is unlike `V2Coachmark` where the `children` prop contains the coachmark content itself.
```jsx live
() => {
const [isStarted, setIsStarted] = useState(false);
return (
setIsStarted(false)}
onComplete={() => setIsStarted(false)}
>
setIsStarted(true)}>
Start Tour
Coachmark Tour Target Content
);
};
```
## Tour Navigation
This example demonstrates navigation controls, multiple steps, position control, and different coachmark types. Users can skip the tour at any time using the close button, and callbacks are provided for navigation events.
```jsx live
() => {
const [isStarted, setIsStarted] = useState(false);
const [tourType, setTourType] = useState('light-border');
return (
{
console.log('Tour skipped');
setIsStarted(false);
}}
onNext={(stepId) => console.log(`Moving to step ${stepId}`)}
onPrevious={(stepId) => console.log(`Going back to step ${stepId}`)}
onComplete={() => {
console.log('Tour completed');
setIsStarted(false);
}}
>
setIsStarted(true)} isDisabled={isStarted}>
Start Tour
{Array.from({ length: 3 }).map((_, i) => {
const stepId = i + 3;
return (
Item {stepId - 2}
);
})}
Step 6: Final Step (Below)
);
};
```
## Step Ordering
Steps are displayed in the order of their `stepId` regardless of their DOM order, giving you full control over the tour flow.
```jsx live
() => {
const [isStarted, setIsStarted] = useState(false);
return (
setIsStarted(false)}
onComplete={() => setIsStarted(false)}
>
setIsStarted(true)}>
Start Ordered Tour
DOM Order: 1st, Tour Order: 3rdDOM Order: 2nd, Tour Order: 1stDOM Order: 3rd, Tour Order: 2nd
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: container
category: Layout
title: Container
description: A responsive container component that adjusts padding based on screen size and safe area insets.
design: https://www.figma.com/design/pXUASUBRjlvl1ZEUVuqniE/Landscape-A11y?node-id=647-37364
---
```jsx
import { Container } from '@uhg-abyss/mobile';
```
The `Container` adjusts its padding based on the following rules:
- **Small Screens (< 480px):** Minimum padding of 16px or the safe area inset, whichever is larger.
- **Medium Screens (480px - 1023px):** Minimum padding of 44px or the safe area inset, whichever is larger.
- **Large Screens (> 1024px):** Padding is calculated dynamically based on the screen width and safe area insets.
## Usage
```jsx live
() => {
return (
{Array.from({ length: 24 }).map((span, index) => {
return (
);
})}
);
};
```
```jsx render
```
---
id: date-input
category: Forms
title: DateInput
description: Capture date input from user.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=18955-105856&t=YLpsLvAcbJ0Le6G5-0
---
```jsx
import { DateInput } from '@uhg-abyss/mobile';
```
Important Note: The scrolling picker portion of this component is currently NOT accessible. The input box is accessible and can be used to enter a date or time with the keyboard.
When a screen reader is active, the button to activate the picker will be hidden.
## Usage
The `DateInput` component allows users to select a date or time from a picker. The picker will display a calendar for date selection and a time picker for time selection.
The time picker is an internal component, but [Calendar](/mobile/ui/calendar) is a separate component that can be used independently.
### Keyboard Entry
Users can enter the date or time with the native keyboard by pressing the input box. The date or time entered can be read from the `value` prop. Use the `onSubmit` prop to handle the action when the submit key is pressed.
The date input will not accept an entry if it is not in the format of `MM/DD/YYYY` with leading zeros. The time input will not accept an entry if it is not in 12-hour `hh:mm AM/PM` format with leading zeros.
## useState
The `useState` hook gets values from the component state. A date value is required and will be displayed in the input box and as the selected date or time on the picker.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Mode
Use the `mode` prop to define the type of picker. The default mode is set to `"date"`
### Date
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
### Time
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Label
Use the `label` prop to display a label above the input menu.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Help Content
The `helpContent` prop is used to display a help icon in the top right of the container, which will display the provided content in a BottomSheet when pressed.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Required
Use the `isRequired` prop to display an asterisk next to the label.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the date picker.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
);
};
```
## Messages
Use the `errorMessage` and `successMessage` props to display a custom error or success message below the menu.
```jsx live
() => {
const [date, setDate] = useState(new Date());
const errorMessage = useRef(true);
const successMessage = useRef(false);
const handleChange = (newDate) => {
if (newDate) {
errorMessage.current = false;
successMessage.current = true;
} else {
errorMessage.current = true;
successMessage.current = false;
}
setDate(newDate);
};
return (
);
};
```
## Excluded Dates
To exclude dates use the `excludeDate` prop. Set a function that receives date as an argument and returns true if date should be disabled. For example, to disable weekends, check if the day is 0 or 6.
```jsx live
() => {
const [date, setDate] = useState(new Date());
return (
{
return date.getDay() === 0 || date.getDay() === 6;
}}
/>
);
};
```
## Min/Max Date
### Date
Use the `minimumDate` and `maximumDate` props to set the min and max dates in the Calendar dropdown.
```jsx live
() => {
const [date, setDate] = useState(new Date());
const minDate = new Date();
const maxDate = new Date();
minDate.setFullYear(minDate.getFullYear() - 1);
maxDate.setFullYear(maxDate.getFullYear() + 1);
return (
);
};
```
### Time
Use the `minimumDate` and `maximumDate` props to set the min and max times in the Time dropdown.
```jsx live
() => {
const [date, setDate] = useState(new Date());
const minDate = new Date();
const maxDate = new Date();
minDate.setHours(7);
maxDate.setHours(19);
return (
);
};
```
## onInvalidEntry
Use the `onInvalidEntry` prop to handle the date validation. The function returns an object
`{ value: Date, input: string, code: number, message: string }` where `value` is the Date instance of the user's attempted entry,
`input` is the string submitted by the user, `code` indicates a custom code that references a specific error and
`message` describes the error.
The explanation of `code` is noted below:
- 0 - Indicates the input date is invalid.
- 1 - Indicates the input is before the minimum date.
- 2 - Indicates the input is after the minimum date.
- 3 - Indicates the input is a disabled date.
```jsx live
() => {
const setFocus = useSetFocus();
const inputRef = useRef();
const [date, setDate] = useState(new Date());
const [dateMessage, setDateMessage] = useState({
success: '',
error: '',
});
const minimumDate = new Date(2024, 0, 1);
const maximumDate = new Date(2024, 2, 31);
const handleInvalidEntry = ({ code, message }) => {
setFocus(inputRef);
if (code === 0) {
setDateMessage({
error: message,
success: '',
});
} else if (code === 1) {
setDateMessage({
error: `${message}: ${minimumDate.toDateString()}`,
success: '',
});
} else if (code === 2) {
setDateMessage({
error: `${message}: ${maximumDate.toDateString()}`,
success: '',
});
} else if (code === 3) {
setDateMessage({
error: message,
success: '',
});
}
};
return (
{
return date.getDay() === 6;
}}
/>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: default-props-provider
category: Providers
title: DefaultPropsProvider
description: An Abyss component that provides default props to all its child components.
---
```jsx
import { DefaultPropsProvider } from '@uhg-abyss/mobile/ui/DefaultPropsProvider';
```
```jsx render
```
## Overview
`DefaultPropsProvider` lets you set default props for multiple components in one place. This helps keep your app consistent and reduces repeated code.
```jsx
{/* ...children */}
```
## How it Works
The provider uses React Context to pass default props down to child components. Each component uses the `useDefaultProps` hook internally to merge the provider's defaults with its own props, with component-specific props taking precedence.
Prop Priority (highest to lowest):
- Props passed directly to the component
- Default props from DefaultPropsProvider
- Component's built-in default props
## Opting Out of Defaults
To opt out of the defaults, you can set the `disableDefaultProviderProps` prop to `true` on the component. This will prevent the component from inheriting any default props set by the provider.
## V2Button
```jsx sandbox
Provider defaultsProvider defaults with color override
Opt out of provider defaults
```
---
id: divider
category: Layout
title: Divider
description: Used to add visual or semantic separation between content.
design: https://www.figma.com/design/wCMblLsq9TxAQvKzY3EfCt/v1.61.0-App-Abyss-UHC-Component-Library?node-id=65731-2323&p=f&t=5FIU5wnT0w5NeJW3-0
sourceIsTS: true
---
```jsx
import { Divider } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Divider',
inputs: [
{
prop: 'orientation',
type: 'select',
options: [
{ label: 'horizontal', value: 'horizontal' },
{ label: 'vertical', value: 'vertical' },
],
defaultValue: 'horizontal'
},
{
prop: 'margin',
type: 'string',
default: '$sm',
},
{
prop: 'height',
type: 'string',
},
{
prop: 'width',
type: 'string',
},
{
prop: 'color',
type: 'string',
defaultValue: '$divider.color.surface.thin'
},
]
}
```
## Usage
```jsx live
() => {
const VerticalDivider = () => (
);
return (
Abyss Divider ComponentAdd visual separation between content
Orientation
Width
Height
Color
);
};
```
## Orientation
Use the `orientation` prop to adjust the orientation to either `horizontal` or `vertical`. The default setting is `horizontal`.
```jsx live
```
```jsx live
```
## Width, Height and Margin
Use the `width` and `height` props to set the desired sizing dimensions. Depending on the orientation, they default to
`2` or `100%` to create a thin line.
Use the `margin` prop to set the margin between the divider and the content it is separating. Default is `$sm`.
When `horizontal` orientation is selected the settings are applied as follows:
- `width` : determines the left-to-right length of the of the divider; default setting is `100%`
- `height` : determines the thickness of the divider; default setting is `2px`
- `margin`: sets the `marginVertical` property
```jsx live
```
When `vertical` orientation is selected the settings are applied as follows:
- `width` : determines the thickness of the divider; default setting is `2px`
- `height` : determines the top-to-bottom length of the of the divider; default setting is `100%`
- `margin`: sets the `marginHorizontal` property
```jsx live
```
## Color
Use the `color` property to set the color of the divider. The two color tokens fit Abyss design guidelines for thin and thick dividers respectively. The default is set to `thin`.
```jsx live
() => {
return (
);
};
```
```jsx render
```
```jsx render
```
## Color
Decorative only component -- does not need to meet minimum contrast ratio.
```jsx render
```
---
id: donut-chart-v2
category: Data Viz
title: V2DonutChart
description: A graphical representation technique that displays data in a circular-shaped graph.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=20095-102112
subDirectory: DonutChart/v2
sourceIsTS: true
---
```jsx
import { V2DonutChart } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2DonutChart',
inputs: [
{
prop: 'progress',
type: 'number',
defaultValue: 20
},
{
prop: 'size',
type: 'number',
defaultValue: 40
},
{
prop: 'animationDuration',
type: 'number',
defaultValue: 500
},
{
prop: 'color',
type: 'string',
defaultValue: '$donut-chart.color.surface.container.green'
},
],
}
```
## Progress
The `progress` prop determines how far the accumulator will move. The prop accepts numbers between `0` and `100`.
The default is `0`.
```jsx live
```
## Animation Duration
The `animationDuration` prop is used to determine how long the donut chart takes to animate (milliseconds).
The default is `500`.
```jsx live
() => {
const [animated, toggle] = useToggle(false);
const progress = animated ? 40 : 0;
return (
);
};
```
## Color
The `color` prop is used to set the color for the donut chart.
The default is `$conditional7`.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
Due to React Native limitations, this component enables keyboard access despite not having an interactive element. This component requires an accessibility label for use with a screen reader, which enables keyboard focus.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: donut-chart
category: Data Viz
title: DonutChart
description: A graphical representation technique that displays data in a circular-shaped graph.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=20095-102112
subDirectory: DonutChart/v1
---
```jsx
import { DonutChart } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'DonutChart',
inputs: [
{
prop: 'progress',
type: 'number',
},
{
prop: 'size',
type: 'number',
},
{
prop: 'animationDuration',
type: 'number',
},
],
}
```
## Progress
The `progress` prop determines how far the accumulator will move. The prop accepts numbers between `0` and `100`.
The default is `0`.
```jsx live
```
## Animation Duration
The `animationDuration` prop is used to determine how long the donut chart takes to animate (milliseconds).
The default is `1000`.
```jsx live
() => {
const [animated, toggle] = useToggle(false);
const progress = animated ? 40 : 0;
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
Due to React Native limitations, this component enables keyboard access despite not having an interactive element. This component requires an accessibility label for use with a screen reader, which enables keyboard focus.
---
id: expandable-text-block
category: Typography
title: ExpandableTextBlock
description: Displays a text block that can be expanded or collapsed.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/1Uml7LO8NTEWoBUAl4DTaG/Abyss-Mobile?type=design&node-id=18955-106021&t=DfyeirEdeaLCVZP9-0
---
```jsx
import { ExpandableTextBlock } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'ExpandableTextBlock',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'numberOfLines',
type: 'number',
},
{
prop: 'showLess',
type: 'boolean',
},
]
}
Lorem ipsum dolor sit amet, adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Consectetur adipiscing elit pellentesque habitant morbi tristique senectus et. Penatibus et magnis dis parturient montes. Diam in arcu cursus euismod quis viverra nibh cras pulvinar. Lorem mollis aliquam ut porttitor.
```
## Props and Usage
Children are required to use `ExpandableTextBlock`.
The `numberOfLines` prop is used to control the number of lines shown while `ExpandableTextBlock` is closed. The default for `numberOfLines` is 2.
The `showLess` prop is used to give the consumer the ability to shrink the `ExpandableTextBlock`. The default for `showLess` is `false`.
The `onLinkPress` prop can be used when pressing the more/less link needs a callback function. This can take in `expanded` as an argument.
```jsx live
() => {
const lorum = `Lorem ipsum dolor sit amet, adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Consectetur adipiscing elit
pellentesque habitant morbi tristique senectus et. Penatibus et magnis dis
parturient montes. Diam in arcu cursus euismod quis viverra nibh cras
pulvinar. Lorem mollis aliquam ut porttitor. Mauris augue neque gravida in
fermentum et sollicitudin ac. Ultrices tincidunt arcu non sodales neque
sodales ut etiam. In hac habitasse platea dictumst. In dictum non
consectetur a erat nam at lectus. Sed nisi lacus sed viverra tellus in hac
habitasse platea. Vitae ultricies leo integer malesuada nunc vel risus
commodo viverra. Sed elementum tempus egestas sed sed risus pretium quam.
Tellus id interdum velit laoreet id donec ultrices.`;
return (
<>
{lorum} {
console.log(
`The text block is now ${expanded ? 'expanded' : 'collapsed'}.`
);
}}
>
{lorum}
>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
Text scales according to Abyss standards. Note that the `numberOfLines` prop also scales according to the font scale.
## Screen Reader Support
Accessibility focus may need to be reset to the start of the text paragraph after the "more" button is pressed. This can be done within your `onLinkPress` function.
```jsx render
```
---
id: floating-action-button
category: Overlay
title: FAB
description: Hovers over content to execute a primary action in the application.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=1-431&t=O2ewq2cTM45gG9ki-0
---
```jsx
import { FAB } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'FAB',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'isActive',
type: 'boolean',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'size',
type: 'string',
},
]
}
Text
```
## Variants
Text can be added to the FAB as a child.
```jsx live
() => {
return (
DefaultChatActiveChatDisabledChat
);
};
```
## Example
Here we are using react's useState hook to manage FAB's active state.
```jsx live
() => {
const [isActive, setIsActive] = useState(false);
return (
App goes here with FAB in the bottom right
{isActive ? The FAB is active : null}
{
console.log('FAB pressed from parent'), setIsActive(!isActive);
}}
>
Chat
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: filter-button
category: CTA
title: FilterButton
description: A button that serves as an entry point to filtering options.
design: https://www.figma.com/design/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-UHC-Abyss-Mobile-App?node-id=104-1483&t=5zdX8H00uo6BCkNJ-0
---
```jsx
import { FilterButton } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'FilterButton',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'primary', value: 'primary' },
{ label: 'secondary-a', value: 'secondary-a' },
{ label: 'secondary-b', value: 'secondary-b' },
],
},
],
}
```
## Label
Use the `label` prop to set the label of the FilterButton. The label can be a filter count or 'filter'. If there is no count, the secondary variants should have the label of 'filter' passed in.
```jsx live
() => {
const [value, setValue] = useState([]);
return (
{
console.log('primary FilterButton pressed');
}}
/>
{
console.log('secondary-a FilterButton pressed');
}}
/>
{
console.log('secondary-b FilterButton pressed');
}}
/>
);
};
```
## Variant
Use the `variant` prop to change the style of the `FilterButton`. You can set the value to `'primary'`, `'secondary-a'`, and `'secondary-b'`. Please follow design guidelines for each variants use case.
```jsx live
Primary}
right={
{
console.log('primary FilterButton pressed');
}}
/>
}
/>
Secondary A {
console.log('secondary-a FilterButton pressed');
}}
/>
Secondary B {
console.log('secondary-b FilterButton pressed');
}}
/>
```
```jsx render
```
```jsx render
```
---
id: font-scale
category: Layout
title: FontScale
description: Used to layout UI elements conditionally by font size.
---
```jsx
import { FontScale } from '@uhg-abyss/mobile';
```
## Usage
Used to conditionally display elements based on the device font scale. The condition is based on the `smallerThan` or `largerThan` props (or both of them at the same time).
```jsx live
An icon will appear to the right when the window size is at least extra
large:
An icon will appear to the right when the window size is less than extra
large:
An icon will appear to the right when the window size is between large and
extra large:
```
## Smaller Than
Use the `smallerThan` prop to specify a font scale that the device must be smaller than for the contents inside the FontScale to display.
```jsx live
An icon will appear to the right when the font scale is less than 150%:
```
## Larger Than
Use the `largerThan` prop to specify a font scale that the device must be greater than or equal to for the contents inside the FontScale to display.
```jsx live
An icon will appear to the right when the window size is at greater than 90%:
```
## Preset Scale Values
As an alternative to using hardcoded number for `smallerThan` and `largerThan`, you can use preset scale values to ensure consistency across your app. (Scale values are taken from the app's theme configuration.) Possible values are `$xs`, `$sm`, `$md`, `$lg`, and `$xl`.
```jsx live
An icon will appear to the right when the window size is at least the size of
the $md breakpoint:
```
```jsx render
```
---
id: footer
category: Content
title: Footer
description: A footer is a component that appears at the bottom of the screen.
design: https://www.figma.com/design/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-UHC-Abyss-Mobile-App?node-id=104-2016&p=f&t=jLxszkqX1mcOC0WV-0
sourceIsTS: true
---
```jsx
import { Footer } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Footer',
inputs: [
{
prop: 'variant',
type: 'select',
defaultValue: 'nested',
options: [
{ label: 'nested', value: 'nested' },
{ label: 'sticky', value: 'sticky' },
]
},
{
prop: 'direction',
type: 'select',
defaultValue: 'vertical',
options: [
{ label: 'vertical', value: 'vertical' },
{ label: 'horizontal', value: 'horizontal' },
]
},
]
}
```
## Variant
Use the `variant` prop to set the variant of the footer. The footer can be `'nested'` or `'sticky'`.
```jsx live
Nested FooterSticky Footer
```
## Direction
Use the `direction` prop to set the direction of the items in the footer. The footer should house
up to three buttons in its vertically staked variant and up to two button in its horizontally stacked variant.
```jsx live
Horizontal FooterVertical Footer
```
## Header
Use the `header` prop to set the header of the footer.
```jsx live
```
```jsx render
```
```jsx render
```
---
id: form-provider
category: Providers
title: FormProvider
description: Adds form functionality to Abyss inputs.
sourceIsTS: true
---
```jsx
import { FormProvider } from '@uhg-abyss/mobile';
```
## Usage
Use `FormProvider` along with the [useForm](/mobile/hooks/use-form) hook in order to better manage your forms and fully utilize the capabilities of form management within Abyss. To achieve this you will need to wrap all form fields and the submission button with the `FormProvider` component and provide state through usage of `useForm`.
Please see examples below for additional props to pass into the `FormProvider` and go to [useForm](/mobile/hooks/use-form) for detailed documentation on how to configure your forms and take advantage of all the available features.
```jsx live
() => {
const form = useForm();
const onSubmit = (data) => {
console.log('data', data);
// Do something on submit
};
return (
);
};
```
---
id: global-app-process
category: Feedback
title: GlobalAppProcess
description: A type of notification message that communicates system status or background processes.
design: https://www.figma.com/design/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-UHC-Abyss-Mobile?node-id=931-196076&node-type=frame&t=ti8wesv8clRgQn1m-0
---
```jsx
import { GlobalAppProcess } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'GlobalAppProcess',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'actionText',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'info', value: 'info' },
]
},
{
prop: 'isVisible',
type: 'boolean'
},
]
}
```
## Label
Use the `label` prop to set the label of the global app process. Setting a label is required.
```jsx live
```
## Variants
Use the `variant` property to set the color and icon of the `GlobalAppProcess`.
The options are `success`, `warning`, `error`, and `info`. All variants have the default icons shown below. `info` is the only variant with a built-in icon animation.
```jsx live
```
## Icon
Use the `icon` property to pass in a specific `Icon` component. Note that if the icon on the `info` variant is replaced it will not animate.
```jsx live
}
label="Search Title"
variant="info"
/>
```
## Button Text
Use the `actionText` prop to add a button to the right of the process banner. This will adjust the layout of the banner from centered to stretched.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(true);
return (
{
setIsVisible(false);
}}
/>
);
};
```
## onActionPress
Use the `onActionPress` property to handle the action when the button is pressed.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(true);
return (
{
setIsVisible(false);
}}
/>
);
};
```
## isVisible
Use the `isVisible` prop to change the visibility of the process banner.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(true);
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: grid
category: Layout
title: Grid
description: Provides a brief message about the app processes.
---
```jsx
import { Grid } from '@uhg-abyss/mobile';
```
## Space
Use the `space` prop to determine the amount of space between elements in the grid.
```jsx live
```
## Span
### Number
Regardless of viewport width, the span will remain the same for these columns. Change the span by using [column spans] of the parent container.
```jsx live
12333366
```
### Percent
Regardless of viewport width, the span will remain the same for these columns. Change the span by using percentages of the parent container.
```jsx live
100%33%33%33%20%20%20%20%20%
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: heading
category: Typography
title: Heading
description: Creates appropriately sized heading elements.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9470%3A32790
---
```jsx
import { Heading } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Heading',
inputs: [
{
prop: 'children',
type: 'string',
defaultValue: 'Heading',
},
{
prop: 'offset',
type: 'select',
options: [
{ label: '1', value: '1' },
{ label: '2', value: '2' },
{ label: '3', value: '3' },
{ label: '4', value: '4' },
{ label: '5', value: '5' },
{ label: '6', value: '6' },
],
},
{
prop: 'color',
type: 'select',
options: [
{ label: '$primary1', value: '$primary1' },
{ label: '$info1', value: '$info1' },
{ label: '$gray3', value: '$gray3' },
{ label: 'lightseagreen', value: 'lightseagreen' },
{ label: '#ff0000', value: '#ff0000' },
],
},
{
prop: 'textAlign',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'center', value: 'center' },
{ label: 'right', value: 'right' },
],
},
]
}
Heading
```
## Set Global Heading Font
One of the limitations of our library is the inability to install fonts into applications. Because of this, we have reserved a special token, `$heading`, to be added in the createTheme function, which will add the font to all Heading components globally.
In the example below, the font 'UHCSerif' is set as the heading font and will now be applied to all Heading components.
```jsx
import { ThemeProvider, createTheme } from '@uhg-abyss/mobile';
const theme = createTheme('uhc', {
theme: {
fonts: {
heading: 'UHCSerif',
},
},
});
const App = () => {
return ...;
};
```
## Offset
If you want to have heading levels relative to the current level, you can provide an offset prop.
These are equivalent to using a heading element in HTML. A Heading with an offset of 1 would be the equivalent of an `
`.
Headings 1-4 have a default color of `$primary1` and Headings 5 & 6 have a default color of `$black`.
You can use `offset={1|2|3|4|5|6}`.
```jsx live
Heading 1Heading 2Heading 3Heading 4Heading 5Heading 6
```
## Level
Headings 5 and 6 have an optional property called `level` that allows you to use a lighter version of the text. The default is level 1, the heavier version. The level two prop makes the
heading lighter.
```jsx live
Heading 5 (level 1)
Heading 5 (level 2)
Heading 6 (level 1)
Heading 6 (level 2)
```
## Color
Use the `color` property to set the color of the text. The default is set to `$primary1`.
```jsx live
My BenefitsMy BenefitsMy BenefitsMy Benefits
```
## Text Align
Use the `textAlign` prop to change the alignment of the text. Options include `left`, `center` and `right`.
The default is set to `left`.
```jsx live
Left Aligned HeadingCenter Aligned HeadingRight Aligned Heading
```
```jsx render
, and so on',
default: '1',
},
{
name: 'textAlign',
type: '"left" | "center" | "right"',
description: 'Specifies text alignment of the heading text',
default: 'left',
},
{
name: 'color',
type: 'string',
description: 'Set the color of the heading text',
default: 'Headings 1-4: "$primary1", Headings 5-6: "$black"',
},
{
name: 'animated',
type: 'boolean',
description: 'Flag to make component animatable',
default: 'false',
},
{
name: 'level',
type: '1 | 2',
description:
'Set the level of the heading. Used for offset 5 and 6 headings',
default: '1',
},
{
name: 'fontFamily',
type: 'string',
description: 'Set the font family of the heading',
},
]}
/>
```
```jsx render
```
```jsx render
```
---
id: home-widget
category: Content
title: HomeWidget
description: A component of an interface, that enables a user to perform a function or access a service.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=12334-61355&t=hhJi0b2ytlH4Ftjo-0
---
```jsx
import { HomeWidget } from '@uhg-abyss/mobile';
```
## HomeWidget Card Title & Background
Entering a value into the `title` prop will display a header with title and accompanying Background image when applicable.
You can customize the Background using the `headerBackground` prop.
```jsx live
() => {
const CostIcon = styled(Image, {
position: 'absolute',
zIndex: -20,
top: -100,
right: -30,
width: 550,
height: 250,
});
const Cost = ({ children, label, number }) => {
return (
{label}
${number}
{children}
);
};
return (
}
>
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
>
);
};
```
## HomeWidget Customization
A title can be added to `HomeWidget` via the `title` prop.
Content is added to `HomeWidget` with children. Any content added will be placed inside a horizontal flex container with justifyContent set to `space-between`. By default, content is placed underneath the title, but this can be changed via the `headerAlignment` prop.
The `color` prop is used to change the widget color. If a dark color is applied, the text color will adjust to `$white`, this can be overridden via the `titleColor` prop. Use the `activeColor` prop to set the pressed color. If nothing is passed the color will stay the same when pressed.
The title position can be adjusted via the `headerAlignment` prop, the title can either be above or below the widget content. The default for `headerAlignment` is `top`
A subtitle can be placed below the widget title via the `subtitle` prop.
```jsx live
() => {
return (
console.log('widget has been pressed')}
subtitle="Sub-title"
>
Total Due
$1043.43
console.log('widget has been pressed')}
>
Total Due
$1043.43
console.log('widget has been pressed')}
headerAlignment="bottom"
>
);
};
```
## Widget Layout
`HomeWidget` will be laid out automatically when placed inside of `HomeWidget.Card`. The widgets will be laid out in a grid with two columns and will grow when given space.
`HomeWidget` can be made to occupy the entire width of the card by setting `span={2}`.
The widget title will wrap to be two lines if no notification is present, but only one line if a notification is present.
```jsx live
() => {
return (
console.log('widget has been pressed')}
>
Available
$600
console.log('widget has been pressed')}
>
Available
$425
console.log('widget has been pressed')}
>
Total Due
$1043.43
);
};
```
## Custom containers
`HomeWidget` can also be used on its own or with a custom container. When standing alone, the `HomeWidget` will grow to full width of its container.
[Grid](/mobile/ui/grid) is recommended to control the layout when using a custom container.
```jsx live
() => {
return (
console.log('widget has been pressed')}
headerAlignment="bottom"
>
console.log('widget has been pressed')}
headerAlignment="bottom"
>
console.log('widget has been pressed')}
>
Available
$600
);
};
```
```jsx live
() => {
return (
console.log('widget has been pressed')}
>
);
};
```
## Example
```jsx live
() => {
const CostIcon = styled(Image, {
position: 'absolute',
zIndex: -20,
top: -100,
right: -30,
width: 550,
height: 250,
});
const Cost = ({ children, label, number }) => {
return (
{label}
${number}
{children}
);
};
const RemainingCost = ({ label, number }) => {
return (
{label}
${number + ' '}
Remaining
);
};
return (
}
style={{ padding: 6 }}
title="Spending & Rewards"
>
console.log('widget has been pressed')}
>
Medical / Rx
Dental
Vision
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
>
console.log('widget has been pressed')}
subtitle="Medical In-Network"
>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
HomeWidget scales according to Abyss standards. Dynamic type causes some elements to reconfigure in a stacked format. Any [IconBrand](/mobile/brand/uhc/icon-brand/?tab=accessibility) should set `disableScaling={true}`. The internal chevron icon will only scale to 130%.
```jsx render
```
```jsx render
```
---
id: i18n-provider
category: Providers
title: I18nProvider
description: Used to provide i18n data to the application.
---
```jsx
import { I18nProvider } from '@uhg-abyss/mobile/ui/I18nProvider';
```
## Usage
Abyss supports overriding the default i18n object by using the `I18nProvider` component. The `I18nProvider` component takes a `translations`
prop that is an object containing the translations to either override the default translations with or to provide custom translations. The
translations object for overrides will be in the following format:
```jsx
{
[commonWord]: 'Translated Value',
[componentName]: {
[key]: 'Translated Value',
},
}
```
THe `commonWord` key is used to override the default translations for common words used in Abyss component. The `componentName` key with an object
is for words within specific Abyss components that allow an additional scope to other keys. Below is an example of a few of the words in our default i18n object:
```jsx
{
disabled: 'Disabled',
submit: 'Submit',
SearchBar: {
clearText: 'Clear Text',
},
TextField: {
clear: 'clear',
charactersRemaining: '{{count}} characters remaining',
},
}
```
When using the `t` function from the [useTranslate](/mobile/hooks/use-translate) hook or the [Translate](/mobile/ui/translate) component, the key will be in dotted
notation. For example, the key `'SearchBar.clearText'` will be used to get the value `'Clear Text'` from the i18n object.
Our default i18n object can be seen [here](https://github.com/uhc-tech/abyss/blob/main/packages/abyss-mobile/src/tools/i18n/translations/en.ts)
## Example
Let's use the [TextField](/mobile/ui/text-field) component as an example. The `TextField` component has a text block that
displays the remaining characters available to be typed in the text field when the `maxLength` prop is used.
```jsx render
() => {
const [value, setValue] = useState('State Default Value');
return (
);
};
```
Internally, we use the `'TextField.charactersRemaining'` key to get value in our i18n object. This value can be overridden with
the `translations` prop in the `I18nProvider` component. Let's change the value of the `'TextField.charactersRemaining'` key to place
the amount of characters left at the end of the string.
```jsx live-expanded
() => {
const [value, setValue] = useState('State Default Value');
return (
);
};
```
## Language Translations
We can use the same idea to translate text into different languages.
```jsx live
() => {
const [value, setValue] = useState('Valor por defecto');
return (
);
};
```
## Custom I18n
You can also use the `I18nProvider` component to not only override the default values used in Abyss components, but you provide your own custom custom values .
Those values can then consumed later using the [useTranslate](/mobile/hooks/use-translate) hook or the [Translate](/mobile/ui/translate) component.
```jsx live
const MyComponent = () => {
const { t } = useTranslate();
return (
{t('myCustomText')}{t('nested.key')}
);
};
render(() => {
return (
);
});
```
## Related Links
- [useTranslate](/mobile/hooks/use-translate)
- [Translate](/mobile/ui/translate)
```jsx render
```
---
id: icon
category: Media
title: Icon
description: Used to implement icons and adapt their properties.
# design: https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/Abyss-Design-System?node-id=0%3A10709
---
```jsx
import { Icon } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Icon',
inputs: [
{
prop: 'size',
type: 'string',
},
{
prop: 'title',
type: 'string',
},
{
prop: 'color',
type: 'string',
},
]
}
() => {
const customIcon = (
``
);
return (
{customIcon}
);
};
```
## Usage
Use `Icon` to implement custom SVG icons
```jsx live
{``}
{``}
```
## Colors
Use the `color` property to adjust the color of a Google material icon. Theme colors can be found in the [Colors](/brand/colors) documentation section or a hex code can be used. The default color is set to the theme `'interactive1'`.
```jsx live
{``}
{``}
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific preset size or number. The default is set to `24px` || `$md`. The size prop can take in px or tokens.
Token sizes: `$xs`: 16 `$sm`: 20 `$md`: 24 `$lg`: 40 `$xl`: 48
```jsx live
() => {
const customIcon = ``;
return (
{customIcon}
{customIcon}
{customIcon}
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: icon-material
category: Media
title: IconMaterial
description: Used to implement material icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=1%3A432
---
```jsx
import { IconMaterial } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconMaterial',
inputs: [
{
prop: 'icon',
type: 'string',
},
{
prop: 'color',
type: 'string',
},
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'filled', value: 'filled' },
{ label: 'outlined', value: 'outlined' },
],
},
]
}
```
## Icons
Use the `icon` property to adjust which icon is being selected.
```jsx live
```
## Colors
Use the `color` property to adjust the color of a Google material icon. Theme colors can be found in the [Colors](/mobile/brand/uhc/colors) documentation section or a hex code can be used. The default color is set to the theme `'interactive1'`.
```jsx live
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number or token. The default size is set to 24.
Token sizes: `$xs`: 16 `$sm`: 20 `$md`: 24 `$lg`: 40 `$xl`: 48
```jsx live
```
## Material Icon Variants
Use the `variant` property to change the style of Material icons. The default variant is `filled`.
```jsx live
```
Abyss uses Google's Material Design System iconography that is simple, modern, friendly,
and sometimes quirky. Each icon is created using Google's design guidelines to depict
in simple and minimal forms the universal concepts used commonly throughout user
interfaces. Ensuring readability and clarity at both large and small sizes, these
icons have been optimized for common platforms and display resolutions.
The source for these design icons can be found in the Material Icons Library.
```jsx render
```
---
id: icon-symbol
category: Media
title: IconSymbol
description: Used to implement material symbol icons and adapt their properties.
design: https://www.figma.com/file/anZoHg026SyKJHWGJ7Vf4Q/Abyss-Icons?node-id=1%3A432
---
```jsx
import { IconSymbol } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'IconSymbol',
inputs: [
{
prop: 'icon',
type: 'string',
},
{
prop: 'color',
type: 'string',
},
{
prop: 'size',
type: 'string',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'filled', value: 'filled' },
{ label: 'outlined', value: 'outlined' },
],
},
]
}
```
## Icons
Use the `icon` property to adjust which icon is being selected.
```jsx live
```
## Colors
Use the `color` property to adjust the color of a material symbol icon. Theme colors can be found in the [Colors](/mobile/brand/uhc/colors) documentation section, or a hex code can be used. The default color is set to the theme `'interactive1'`.
```jsx live
```
## Size
Use the `size` property to adjust the size of an icon by setting it to a specific number or token. The default size is set to 24.
Token sizes: `$xs`: 16 `$sm`: 20 `$md`: 24 `$lg`: 40 `$xl`: 48
```jsx live
```
## Material Symbol Variants
Use the `variant` property to change the style of Material symbol icons. The default variant is `filled`.
```jsx live
```
```jsx render
```
---
id: indicator
category: Data Display
title: Indicator
description: Adds an indicator to wrapped elements.
# design: https://www.figma.com/file/tk08Md4NBBVUPNHQYthmqp/branch/sabyctxmnS57eNFcPZQAbi/Abyss-Design-System
---
```jsx
import { Indicator } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Indicator',
inputs: [
{
prop: 'offset',
type: 'number',
defaultValue: 0
},
{
prop: 'overflowCount',
type: 'number',
defaultValue: 99
},
{
prop: 'position',
type: 'select',
options: [
{ label: 'top-start', value: 'top-start' },
{ label: 'top-end', value: 'top-end' },
{ label: 'bottom-start', value: 'bottom-start' },
{ label: 'bottom-end', value: 'bottom-end' },
],
defaultValue: 'top-end',
},
{
prop: 'color',
type: 'string',
defaultValue: '$indicator.color.surface.container',
},
{
prop: 'label',
type: 'string',
},
]
}
Indicator Sandbox
```
## Offset
Use the `offset` prop to change the position of the Indicator. It is useful when the Indicator component is used with children that have border radius.
```jsx live
```
## Color
Use the `color` prop to change the color of the Indicator. Default value is set to `'$error1'`.
```jsx live
```
## Label
Use the `label` prop to add a label to the indicator. A value greater than 99 will display as "99+". Use the `overflowCount` prop to chance the overflow value.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: lagoon-provider
category: Providers
title: LagoonProvider
description: Used to provide Lagoon project table data to the application.
---
```jsx
import { LagoonProvider } from '@uhg-abyss/mobile';
```
## Usage
Applications must be wrapped in the `LagoonProvider` in order to access the Lagoon project data. Through usage of the `useLagoon` hook you can retrieve all table data or pass an optional agrument with the desired table path.
```jsx
```
## Return all project table data
```jsx live
() => {
const tableFunctions = useLagoon();
const allData = Object.keys(tableFunctions).map((key) => {
return { [key]: tableFunctions[key]() };
});
const obj = Object.assign({}, ...allData);
return (
{JSON.stringify(obj, null, 4)}
);
};
```
## Return data for specified table path
```jsx live
() => {
const tablePath = 'lagoonprovider-docs-two';
const tableFunction = useLagoon(tablePath);
const data = { [tablePath]: tableFunction() };
return (
{JSON.stringify(data, null, 4)}
);
};
```
## Fallback
In the event that Lagoon data cannot be retrieved, a `fallback` prop can be used to pass in data with an object
similar to the one expected to be retrieved from the API.
```jsx
```
```jsx render
```
---
id: layout
category: Layout
title: Layout
description: A single or multi-section container used to display content related to a single subject.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/Sk3MrHYxjT39TKDzDU5LBc/Abyss-Mobile?node-id=20334%3A61355
---
# Overview
Layout is a set of organizational components that follow the patterns of Flexbox.
## Layout.Group
Used to align elements in a row.
```jsx sandbox
{
component: 'Layout.Group',
inputs: [
{
prop: 'space',
type: 'number',
},
{
prop: 'alignLayout',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'center', value: 'center' },
{ label: 'right', value: 'right' },
],
},
{
prop: 'alignItems',
type: 'select',
options: [
{ label: 'top', value: 'top' },
{ label: 'center', value: 'center' },
{ label: 'bottom', value: 'bottom' },
],
},
{
prop: 'grow',
type: 'boolean',
},
],
}
Group 1Group 2Group 3
```
## Layout.Stack
Used to align elements in a column.
```jsx sandbox
{
component: 'Layout.Stack',
inputs: [
{
prop: 'space',
type: 'number',
},
{
prop: 'alignLayout',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'center', value: 'center' },
{ label: 'right', value: 'right' },
],
},
{
prop: 'alignItems',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'center', value: 'center' },
{ label: 'right', value: 'right' },
],
},
{
prop: 'grow',
type: 'boolean',
},
],
}
Stack 1Stack 2Stack 3
```
## Layout.Group and Layout.Stack Props
### Space
Use the `space` property to set the spacing for a `Group` or `Stack`. The default is set to `8`.
```jsx live
Group Group 1Group 2Group 3Group - 20px space Group 1Group 2Group 3
```
```jsx live
Stack Stack 1Stack 2Stack 3Stack - 20px space Stack 1Stack 2Stack 3
```
### AlignLayout
Use the `alignLayout` property to indicate the horizontal alignment of the items in a `Group` or `Stack`. For a Group, the possible options are `left`, `center`, and `right`. For a Stack, the possible options are `left`, `center`, and `right`. The default is set to `left` in both cases.
```jsx live
Group - top align - Default Group Top 1Group Top 2Group Top 3Group - center align Group DefaultGroup DefaultGroup DefaultGroup - bottom align Group Bottom 1Group Bottom 2Group Bottom 3
```
```jsx live
Stack - left align - default Stack Left 1Stack Left 2Stack Left 3Stack - center align Stack DefaultStack DefaultStack DefaultStack - right align Stack Right 1Stack Right 2Stack Right 3
```
### AlignItems
Use the `alignItems` property to indicate the alignment of the items in a `Group` or `Stack`. For a `Group` the vertical alignment is adjusted, whereas for a `Stack` the horizontal alignment is adjusted. For a Group, the possible options are `top`, `center`, and `bottom`. For a Stack, the possible options are `left`, `center`, and `right`. The default is set to `center` in both cases.
```jsx live
Group - top align Group Top 1Group Top 2Group Top 3Group - center align - Default Group DefaultGroup DefaultGroup DefaultGroup - bottom align Group Bottom 1Group Bottom 2Group Bottom 3
```
```jsx live
Stack - left align Stack Left 1Stack Left 2Stack Left 3Stack - center align - Default Stack DefaultStack DefaultStack DefaultStack - right align Stack Right 1Stack Right 2Stack Right 3
```
### Grow
Use the `grow` property to indicate whether the grouped components should be stretched to fill the space horizontally. The default is set to `false`.
```jsx live
Group - default OneTwoThreeGroup - grow Item 1Item 2Item 3
```
```jsx live
Stack - default OneTwoThreeStack - grow OneTwoThree
```
### Shrink
Use the `shrink` property to indicate whether the grouped components should be shrunk to fill the space horizontally in a `Group`, to prevent an overflow. The default is set to `false`.
```jsx live
Group - default Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor Group - shrink Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor
```
## Layout.Insert
Used to place elements before and after a central component. Padding is `$sm` and direction is `row`by default.
```jsx live
}
after={}
padding="$sm"
>
Center
```
## Layout.Space
Adds a space of height `space`. Default is `16px`.
```jsx live
OneTwo
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: link
category: Navigation
title: Link
description: Used to navigate to other pages, or sections of a page.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=11579-66904&mode=design&t=lQdpLQ0uWdxbRS9p-0
---
```jsx
import { Link } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Link',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'size',
type: 'select',
options: [
{ label: 'large', value: 'large' },
{ label: 'medium', value: 'medium' },
{ label: 'small', value: 'small' },
],
},
{
prop: 'href',
type: 'string',
},
{
prop: 'underline',
type: 'boolean',
},
]
}
Link Sandbox
```
**The children passed into the link must be a string or an error will appear.**
## Text
Change the children of the link to set the text. Note that the child must be a string.
```jsx live
{
return ;
}}
>
UHC
```
## Size
Use the `size` prop to set the size of the link. The default is set to `large`.
```jsx live
Large Link / 18px
Medium Link / 16px
Small Link / 14px
```
## Underline
The `underline` prop is used to underline the link text. The default is set to `false`.
```jsx live
Normal Link
Underlined Link
```
## Inserting Elements
Insert elements into the Link component using the `before` and `after` props.
To account for press state color, the `before` and `after` props can accept a function whose arguments contain the properties `color` and `isPressed`.
```jsx live
{
return ;
}}
href="https://abyss.uhc.com/"
>
Abyss Docs
{
return (
);
}}
>
Abyss Docs
}
size="small"
>
Abyss Docs
```
## Content Guidelines
The informational (left) icon should be used when the link is being used as a Tooltip. Do not use the right icon in this case. Tooltips can appear as icons only, or with text.
```jsx live
}>
}>What is this?
```
A directional (right) icon should be used when the link will take you to another screen.
```jsx live
}>View results
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: loading-spinner-v2
category: Overlay
title: V2LoadingSpinner
description: Infinite loading spinner.
design: https://www.figma.com/design/wCMblLsq9TxAQvKzY3EfCt/v1.66.0-App-Abyss-UHC-Component-Library?node-id=12985-84753&p=f&t=Q9ZAauYOQC2ugiP4-0
sourceIsTS: true
---
```jsx
import { V2LoadingSpinner } from '@uhg-abyss/mobile';
```
## Overview
Loading Spinner requires the `accessibilityLabel` prop to describe what happens while the loading spinner is active. Common labels are 'Submitting Form', 'Downloading Files', 'Content is loading', etc. Be as descriptive as possible.
```jsx
```
## Size
Loading spinner comes in two sizes, `xs` and `sm`. With the `xs` variant being used solely for use on buttons.
```jsx live
() => {
return (
);
};
```
## Color
The `color` property allows changing the color of the loading spinner.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
const toggleLoading = () => {
setIsLoading(!isLoading);
};
return (
);
};
```
## Alt
The `alt` property changes the color of the loading spinner.
```jsx live
() => {
return (
);
};
```
## Heading
Use the `heading` prop to add text below the spinner. Only available when the size is set to `'sm'`.
```jsx live
```
## Button
The Button component has LoadingSpinner integration. Head over to the [Button](/mobile/ui/button) component documentation to learn more.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
return (
}
accessibilityLabel="Importing data"
onClick={() => setIsLoading(!isLoading)}
>
Submit
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
Following the requirements of WAI-ARIA, Loading Spinner follows the requirements 4.1.3: Status Messages. Status messages are defined by WCAG as messages that provide information on the success or results of a user action, but do not change the user's context (i.e., take focus).
Loading Spinner is programmed through the `accessibilityLabel` property, and has been tested using a screen reader to present a status message to assistive technology without receiving focus.
Adheres to the Status messages WAI-ARIA design pattern.
```jsx live
() => {
return ;
};
```
## Dynamic Type
V2LoadingSpinner does not scale. If the `size` prop is set to "xs" and dynamic type scales past 3XL, then `size` will adjust to "sm".
```jsx render
```
```jsx render
```
```jsx render
```
---
id: loading-spinner
category: Overlay
title: LoadingSpinner
description: Infinite loading spinner.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=16616-88862
---
```jsx
import { LoadingSpinner } from '@uhg-abyss/mobile';
```
## Overview
Loading Spinner requires the `accessibilityLabel` prop to describe what happens while the loading spinner is active. Common labels are 'Submitting Form', 'Downloading Files', 'Content is loading', etc. Be as descriptive as possible.
```jsx
```
## Children
On size `$lg`, the Loading Spinner takes in and displays a child. For branding or icons, you can go to the Brandmark, Icon Material, or Icon Brand page for options.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
const toggleLoading = () => {
setIsLoading(!isLoading);
};
return (
);
};
```
## Size
Loading spinner comes in three sizes, `large, medium, small`. With the `small` variant being used solely for use on buttons. The default setting is set to `size = medium`.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
const toggleLoading = () => {
setIsLoading(!isLoading);
};
return (
);
};
```
## Color
The `color` property allows changing the color of the loading spinner. The default color is based on the inherited `colorScheme`.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
const toggleLoading = () => {
setIsLoading(!isLoading);
};
return (
);
};
```
## Label
Use the `label` prop to add text below the spinner.
```jsx live
```
## Button
The Button component has Loading Spinner integration. Head over to the [Button](/mobile/ui/button) component documentation to learn more.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
return (
}
accessibilityLabel="Importing data"
onClick={() => setIsLoading(!isLoading)}
>
Submit
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
Following the requirements of WAI-ARIA, Loading Spinner follows the requirements 4.1.3: Status Messages. Status messages are defined by WCAG as messages that provide information on the success or results of a user action, but do not change the user's context (i.e., take focus).
Loading Spinner is programmed through the `accessibilityLabel` property, and has been tested using a screen reader to present a status message to assistive technology without receiving focus.
Adheres to the Status messages WAI-ARIA design pattern.
```jsx live
() => {
const [isLoading, setIsLoading] = useState(true);
const toggleLoading = () => {
setIsLoading(!isLoading);
};
return (
);
};
```
## Dynamic Type
LoadingSpinner does not scale. If the `size` prop is set to "small" and dynamic type scales past 3XL, then `size` will adjust to "medium".
---
id: modal
category: Overlay
title: Modal
description: Appears from the bottom of the screen and fills up the entire screen, requiring user action to clear it.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=15291-83943
---
```jsx
import { Modal } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Modal',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'title',
type: 'string',
},
]
}
() => {
const [isVisible, setIsVisible] = useState(false);
return (
);
}
```
## useState
Pass the value from the `useState` hook to the `isVisible` modal prop to set the open state of the modal.
```jsx live
() => {
const [modalVisible, setModalVisible] = useState(false);
return (
}
onActionLeftPress={() => setModalVisible(false)}
>
My text
);
};
```
## Title
Use the `title` prop to set the title of the modal. For accessibility purposes, a title is required.
Please provide a title that accurately describes the content of the modal so a screen reader
can provide this description to the user.
```jsx live
() => {
const [modalVisible, setModalVisible] = useState(false);
return (
Custom Text
);
};
```
## Scrollable
Use the `scrollable` prop to make the content scrollable. Setting the prop to `false` changes the Modal's content container from a ScrollView to a View. Defaults to `true`.
## Action Buttons
Action Buttons can be placed on either the left or right side of the header using the `actionLeft` and `actionRight` props.
Use the `onActionLeftPress` prop to fire a callback when the left action is pressed, and `onActionRightPress` prop to
fire a callback when the right action is pressed.
If one of the actions is an icon, make sure to use the `title` and `isScreenReadable` props on the icon for accessibility.
```jsx live
() => {
const [modalVisible, setModalVisible] = useState(false);
const showToast = () => {
Toast.show({
placement: 'top',
text: 'You clicked the right action button',
variant: 'info',
});
};
return (
}
actionRight={
}
onActionLeftPress={() => setModalVisible(false)}
onActionRightPress={showToast}
>
The left and right side of the header have an action button
Click on the left action button to close the modal
Click on the right action button to display a toast message
);
};
```
## Footer
Use the `footer` prop to place content at the bottom of the modal.
```jsx live
() => {
const [modalVisible, setModalVisible] = useState(false);
const showToast = () => {
Toast.show({
placement: 'top',
text: 'You clicked the right action button',
variant: 'info',
});
};
return (
}
>
);
};
```
## Modal Section
Wrap content in a `Modal.Section` component to add padding to the content.
```jsx live
() => {
const [modalVisible, setModalVisible] = useState(false);
return (
}
onActionLeftPress={() => setModalVisible(false)}
>
This text is inside of the `Modal.Section` component
);
};
```
## onClose
Use `onClose` to close the modal when swiping the modal down on iOS devices.
```jsx
() => {
const [modalVisible, setModalVisible] = useState(false);
return (
}
onActionLeftPress={() => setModalVisible(false)}
onClose={() => setModalVisible(false)}
>
Swipe the modal down
);
};
```
## Advanced Layout
Layouts like BottomSheet and Modal can be used in combination with each other to create flows.
```jsx live
() => {
const team = [
{
firstName: 'Michael',
lastName: 'White',
linkText: 'California',
subText: 'MM/DD/YYYY',
value: '1',
},
{
firstName: 'Thomas',
lastName: 'Musengwa',
linkText: 'Arkansas',
subText: 'MM/DD/YYYY',
value: '2',
},
{
firstName: 'Bailey',
lastName: 'Surowiec',
linkText: 'Illinois',
subText: 'MM/DD/YYYY',
value: '3',
},
{
firstName: 'Pablo',
lastName: 'Zepeda',
linkText: 'California',
subText: 'MM/DD/YYYY',
value: '4',
},
];
const locations = [
{
name: 'Alabama',
value: 'AL',
},
{
name: 'Alaska',
value: 'AK',
},
{
name: 'Arizona',
value: 'AZ',
},
{
name: 'Arkansas',
value: 'AR',
},
{
name: 'California',
value: 'CA',
},
{
name: 'Colorado',
value: 'CO',
},
{
name: 'Connecticut',
value: 'CT',
},
{
name: 'Delaware',
value: 'DE',
},
{
name: 'Florida',
value: 'FL',
},
{
name: 'Georgia',
value: 'GA',
},
{
name: 'Hawaii',
value: 'HI',
},
{
name: 'Idaho',
value: 'ID',
},
{
name: 'Illinois',
value: 'IL',
},
{
name: 'Indiana',
value: 'IN',
},
{
name: 'Iowa',
value: 'IA',
},
{
name: 'Kansas',
value: 'KS',
},
{
name: 'Kentucky',
value: 'KY',
},
{
name: 'Louisiana',
value: 'LA',
},
{
name: 'Maine',
value: 'ME',
},
{
name: 'Maryland',
value: 'MD',
},
{
name: 'Massachusetts',
value: 'MA',
},
{
name: 'Michigan',
value: 'MI',
},
{
name: 'Minnesota',
value: 'MN',
},
{
name: 'Mississippi',
value: 'MS',
},
{
name: 'Missouri',
value: 'MO',
},
{
name: 'Montana',
value: 'MT',
},
{
name: 'Nebraska',
value: 'NE',
},
{
name: 'Nevada',
value: 'NV',
},
{
name: 'New Hampshire',
value: 'NH',
},
{
name: 'New Jersey',
value: 'NJ',
},
{
name: 'New Mexico',
value: 'NM',
},
{
name: 'New York',
value: 'NY',
},
{
name: 'North Carolina',
value: 'NC',
},
{
name: 'North Dakota',
value: 'ND',
},
{
name: 'Ohio',
value: 'OH',
},
{
name: 'Oklahoma',
value: 'OK',
},
{
name: 'Oregon',
value: 'OR',
},
{
name: 'Pennsylvania',
value: 'PA',
},
{
name: 'Rhode Island',
value: 'RI',
},
{
name: 'South Carolina',
value: 'SC',
},
{
name: 'South Dakota',
value: 'SD',
},
{
name: 'Tennessee',
value: 'TN',
},
{
name: 'Texas',
value: 'TX',
},
{
name: 'Utah',
value: 'UT',
},
{
name: 'Vermont',
value: 'VT',
},
{
name: 'Virginia',
value: 'VA',
},
{
name: 'Washington',
value: 'WA',
},
{
name: 'West Virginia',
value: 'WV',
},
{
name: 'Wisconsin',
value: 'WI',
},
{
name: 'Wyoming',
value: 'WY',
},
];
const [data, setData] = useState(team);
const [value, setValue] = useState(data[0].value);
const [member, setMember] = useState(data[0]);
const [isVisible, setIsVisible] = useState(false);
const [showModal, setShowModal] = useState(false);
const getCurrentMember = (data, val) => {
return data.find(({ value }) => value === val);
};
const getLocation = (locations, val) => {
return locations.find(({ value }) => value === val);
};
const showToastMessage = () => {
Toast.show({
text: 'Member changed',
variant: 'success',
});
};
const handlePress = () => {
setIsVisible(true);
};
const updateTeam = (newLocation) => {
const newArr = data.map((member) => {
if (member.value === value) {
member.linkText = newLocation;
}
return member;
});
setData(newArr);
};
const handlePressLink = (value) => {
const currentMember = getCurrentMember(data, value);
setValue(currentMember.value);
setShowModal(true);
};
const handleButtonPress = () => {
const currentMember = getCurrentMember(data, value);
setMember(currentMember);
setIsVisible(false);
showToastMessage();
};
const handleCellPress = (val) => {
const newLocation = getLocation(locations, val);
updateTeam(newLocation.name);
const currentMember = getCurrentMember(data, value);
Toast.show({
text:
currentMember.firstName +
"'s location updated to " +
newLocation.name +
'!',
variant: 'success',
});
};
const TextView = styled('View', {
justifyContent: 'center',
paddingLeft: 9,
});
const Content = styled('View', {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
backgroundColor: '$primary1',
padding: '$md',
});
return (
{'For ' + member.firstName}
{member.linkText}
setIsVisible(false)}
title={'Select a member'}
footer={}
>
{data.map(
({ linkText, value, firstName, lastName, subText }, i) => (
}
>
{subText && (
{subText}
)}
{linkText && (
handlePressLink(value)}
after={
}
>
{linkText}
)}
)
)}
setShowModal(false)}
actionLeft={
}
onActionLeftPress={() => {
setShowModal(false);
}}
>
{locations.map(({ value, name }) => (
handleCellPress(value)}
iconRight={
}
>
))}
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
## Focus Guidance
Abyss does not control the focus of components on the screen when the Modal is toggled off. To meet
accessibility guidelines, the focus must be set to the previous node when closed. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For example, if a button is pressed to open a Modal, focus must return to that button once the Modal is closed, so that a screen reader or keyboard user may continue using the app where they left off.
```jsx render
```
---
id: navigation-container
category: Navigation
title: NavigationContainer
description: Responsible for managing app state and linking your top-level navigator to the app environment.
---
```jsx
import { NavigationContainer } from '@uhg-abyss/mobile';
```
The container takes care of platform specific integration and provides various useful functionality:
- Deep link integration with the linking prop.
- Notify state changes for screen tracking, state persistence etc.
- Handle system back button on Android by using the BackHandler API from React Native.
## Usage
```jsx
import { NavigationContainer, createStackNavigator } from '@uhg-abyss/mobile';
const Stack = createStackNavigator();
export default function App() {
return (
{/* ... */}
);
}
```
## Initial State
The `initialState` prop accepts initial state for the navigator. This can be useful for cases such as deep linking, state persistence etc.
**Example:**
```jsx
{/* ... */}
```
Providing a custom initial state object will override the initial state object obtained via linking configuration or from browser's URL. If you're providing an initial state object, make sure that you don't pass it on web and that there's no deep link to handle.
## State Change
The `onStateChange` prop accepts a function that gets called every time navigation state changes. It receives the new navigation state as the argument.
You can use it to track the focused screen, persist the navigation state etc.
**Example:**
```jsx
console.log('New state is', state)}
>
{/* ... */}
```
## onReady
The `onReady` prop accepts a function which is called after the navigation container and all its children finish mounting for the first time. You can use it for:
Making sure that the ref is usable. See docs regarding initialization of the ref for more details.
Hiding your native splash screen
**Example:**
```jsx
console.log('Navigation container is ready')}
>
{/* ... */}
```
## onUnhandledAction
The `onUnhandledAction` prop accepts a function which is called when a navigation action is not handled by any of the navigators.
By default, a development-only error message will be shown when an action was not handled. You can override the default behavior by providing a custom function.
## Linking
The `linking` props handles configuration for linking integration used for deep linking, URL support in browsers etc.
**Example:**
```jsx
import { NavigationContainer } from '@uhg-abyss/mobile';
function App() {
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Home: 'feed/:sort',
},
},
};
return (
Loading...}>
{/* content */}
);
}
```
## Fallback
The `fallback` prop is a React Element to use as a fallback while we resolve deep links. Defaults to `null`.
If you have a native splash screen, please use `onReady` instead of fallback prop.
**Example:**
```jsx
Loading...}>
{/* content */}
```
## Independent
Use the `independent` prop when the navigation container should be independent of parent containers. If this is not set to true, this container cannot be nested inside another container. Setting it to true disconnects any children navigators from parent container.
You probably don't want to set this to true in a typical React Native app. This is only useful if you have navigation trees that work like their own mini-apps and don't need to navigate to the screens outside of them.
```jsx render
```
---
id: needhelp
category: CTA
title: NeedHelp
description: Provides in-app help content, always at the bottom of the page
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=36393-5275&mode=design&t=kg0BV3Q6dFmAIOBa-0
---
```jsx
import { NeedHelp } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'NeedHelp',
inputs: [
{
prop: 'title',
type: 'string',
},
{
prop: 'description',
type: 'string'
},
]
}
Go To Results
```
## Title and Description
The `title` and `description` props are used to set the title and description of NeedHelp.
Both props are required. The `description` can also take a node.
```jsx live
}
>
Go To Results
```
## Children
Add Children to the NeedHelp component by simply placing elements between the NeedHelp tags. Children should be used for adding either a link or button.
Links and buttons can be added with the `NeedHelp.Link` and `NeedHelp.Button` components, respectively.
```jsx live
}
>
Go To Results
Claims can be found from a shortcut on the homescreen. Tap the button
below to go to your claims.
}
>
My Claims
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: nib-group
category: CTA
title: NibGroup
description: Nibs are pressable components used within a group for displaying pre-engineered copy or user-generated information.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=28575%3A52270
---
```jsx
import { NibGroup } from '@uhg-abyss/mobile';
```
## Icon
Use the `icon` prop to insert an icon before the text element. The Brand icon should have `variant={'twotone'}` and be paired with a pre-engineered copy, while the Material icon should have the props `color={'$gray3'} variant={'outlined'}` and be paired with user generated information. See Figma for more details.
```jsx live
() => {
const NibList = [
}
>
Primary care providers
,
}
>
Search History
,
];
return (
{NibList}
);
};
```
## onPress
Use the `onPress` function to handle the action when a Nib is pressed.
```jsx live
() => {
const handlePress = () => {
console.log('Pressed');
};
return (
}
>
Primary care providers in Minneapolis, MN
);
};
```
## NibGroup
Nibs must be wrapped in a group using `NibGroup`.
### Type
Use the `type` prop to determine how the Nib Group will be displayed. By default the type is set to `list`.
### List
Nibs placed in a list will be displayed in rows of two. When the font scale doubles on a mobile device, the nibs will grow to the full width of the container.
```jsx live
() => {
const NibList = [
}
>
Primary care providers
,
}
>
Primary care providers
,
}
>
Primary care providers
,
];
return (
{NibList}
);
};
```
### Carousel
Nibs placed in a carousel will be organized on a slide.
```jsx live
() => {
const NibList = [
}
>
Primary care providers in the Essentia Health system
,
}
>
Primary care providers in the Essentia Health system in Minneapolis,
Minnesota
,
}
>
Primary care providers in the Essentia Health system in Eden Prairie,
Minnesota
,
}
>
Primary care providers in the Essentia Health system in Duluth, Minnesota
,
];
return (
{
console.log('cell pressed');
}}
>
{NibList}
);
};
```
### Sizes
Use the `size` prop to determine the size of the Nibs. By default, `size` is set to `small`. Following design guidelines, Nibs using Material Icons and pre-engineered copy should only use the `small` variant. Nibs displaying user-generated information can use `medium` or `large` depending on the anticipated content size.
```jsx live
() => {
const NibList = [
}
>
Primary care providers in the Essentia Health system
,
}
>
Primary care providers in the Essentia Health system in Minneapolis,
Minnesota
,
}
>
Primary care providers in the Essentia Health system in Eden Prairie,
Minnesota
,
}
>
Primary care providers in the Essentia Health system in Duluth, Minnesota
,
];
return (
Small
}
>
Primary care providers
}
>
Primary care providers
Medium
{NibList}
Large
{NibList}
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: notification
category: Feedback
title: Notification
description: A container used to display information to the user.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=42686-245323&mode=design&t=i3zoWjm6y2FTIEfZ-0
---
```jsx
import { Notification } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Notification',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'seen',
type: 'boolean',
},
]
}
Notification Sandbox
```
## Basic usage
The content of the `Notification` component is made up `children` and `date`. The `date` prop is required and takes a Javascript Date object.
```jsx live
() => {
const [value, setValue] = useState(false);
const [value2, setValue2] = useState(false);
const date1 = new Date();
const date2 = new Date(2022, 3, 11);
return (
Add your dependents to your account to view their claims and coverage.
Your claim has been processed. View your Explanation of Benefits.
);
};
```
## Seen
The `seen` prop handles the state of the Notification. When `true` the text of the component is bold, with a round indicator. `onPress` will be called once the Notification is pressed.
```jsx live
() => {
const [value, setValue] = useState(false);
const [value2, setValue2] = useState(false);
const date1 = new Date();
const date2 = new Date(2021, 7, 21);
return (
setValue(true)} date={date1}>
New! Now you can get care cost estimates then compare, save and share
them.
setValue2(true)} date={date2}>
Go paperless and save time! Sign up for electronic delivery of your
Explanation of Benefits.
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: number-stepper
category: Controls
title: NumberStepper
description: A two-segment UI control used to incrementally increase or decrease a numeric value.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=52553-4919&mode=design&t=jeurw9GyqLDTHSBG-0
---
```jsx
import { NumberStepper } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'NumberStepper',
inputs: [
{
prop: 'maximumValue',
type: 'number',
default: 99,
},
{
prop: 'minimumValue',
type: 'number',
default: 0,
},
{
prop: 'title',
type: 'string',
},
{
prop: 'description',
type: 'string'
},
{
prop: 'isDisabled',
type: 'boolean'
},
]
}
() => {
const [value, setValue] = useState(0)
return(
);
};
```
## useState
The `useState` hook gets the value from the component state. It is required to pass in the starting number to the `value` prop.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
## Title
Use the `title` prop to set the title for the input. It is required to pass in a string to the `title` prop.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
## Description
Use the `description` prop to set the description for the input.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
## Min and Max Values
Use the `minimumValue` and `maximumValue` to constrain the stepper to a specific range. By default this range is 0-99.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
## Disabled
Use the `isDisabled` prop to disable the stepper. By default, the add or remove buttons disable when the min or max is reached.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
## Error Message
Use the `errorMessage` prop to display a message below the description.
```jsx live
() => {
const [value, setValue] = useState(1);
return (
);
};
```
```jsx render
```
```jsx render
```
## Dynamic Type
AX5 reorders items to a vertical stack.
```jsx render
```
---
id: overlay
category: Layout
title: Overlay
description: Semi-transparent overlay with a cutout, for use with the camera to scan barcodes.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/fg0s3SgvOxjhYn4q6HuCS0/Abyss-Mobile?node-id=19209-94534&t=zrt5RmcAOzZcdk3r-0
---
```jsx
import { Overlay } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Overlay',
inputs: [
{
prop: 'color',
type: 'string',
},
{
prop: 'frameHeight',
type: 'number',
},
{
prop: 'frameRadius',
type: 'number',
},
{
prop: 'sideWidth',
type: 'number',
},
{
prop: 'topHeight',
type: 'number',
},
{
prop: 'opacity',
type: 'slider',
minValue: 0,
maxValue: 1,
step: 0.1,
},
]
}
() => {
return (
);
}
```
## Header
Set the `header` prop to a React component to have that component shown above the overlay.
```jsx live
const Container = styled('View', {
minHeight: 300,
});
const TextContainer = styled('View', {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-around',
alignItems: 'center',
});
const Header = styled('View', {
backgroundColor: '$black',
padding: 16,
alignItems: 'center',
justifyContent: 'center',
});
const HeaderText = styled('Text', {
color: '$white',
});
render(() => {
return (
This is the header
}
>
TestingTestingTesting
);
});
```
## Footer
Set the `footer` prop to a React component to have that component shown below the overlay.
```jsx live
const Container = styled('View', {
minHeight: 300,
});
const TextContainer = styled('View', {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-around',
alignItems: 'center',
});
const FooterContainer = styled('View', {
backgroundColor: '$black',
padding: 16,
alignItems: 'center',
justifyContent: 'center',
});
const FooterText = styled('Text', {
color: '$white',
});
render(() => {
return (
This is the footer
}
>
TestingTestingTesting
);
});
```
```jsx render
```
```jsx render
```
---
id: popover-v2
category: Layout
title: V2Popover
description: A popover displays content on top of the page in a separate container and requires user action.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=31310-52671&mode=design&t=Ra4lP896wr2B96P7-0
subDirectory: Popover/v2
sourceIsTS: true
---
```jsx
import { V2Popover } from '@uhg-abyss/mobile';
```
## useState
Pass the value from the `useState` hook to the `isVisible` prop to set the open state of the popover.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
media={Media Content}
content={Content Section}
footer={}
>
);
};
```
## Heading
Use the `heading` prop to set the heading of the popover. For accessibility purposes, a heading is required.
Please provide a heading that accurately describes the content of the popover so a screen reader
can provide the description to the user.
Use the `headingSize` prop to set the size of the heading. The `headingSize` prop accepts `small` and `large` as values.
The default size is `large`.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [isVisible2, setIsVisible2] = useState(false);
return (
setIsVisible(false)}
footer={}
>
);
};
```
## Paragraph
Use the `paragraph` prop to add a description below the heading. The paragraph should be concise and clear and must not expand on more than 4 lines.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
footer={}
>
);
};
```
## Content
Use the `content` prop to add custom content below the paragraph.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
content={
The content section is where you can add custom content.
}
footer={}
>
);
};
```
## Media
Use the `media` prop to add custom content above the heading.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
media={
}
footer={
}
>
);
};
```
## Footer
Use the `footer` prop to place content at the bottom of the popover. The popover must always have at least one button, so users can close it.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
footer={
}
>
);
};
```
## onClose
Use the `onClose` function to handle the action when close button is triggered or when the background is pressed.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
{
setIsVisible(false);
console.log('Popover closed by background tap');
}}
footer={
}
>
);
};
```
```jsx render
```
```jsx render
```
## Dynamic Type
To accommodate for larger text sizes, the popover will scroll when it has grown to have a 16px margin on the top and bottom. Depending on the screen size, the height of the popover when scrollable will vary. The footer does not scroll with the rest of the content. Please follow design guidelines when deciding the amount of content to place within popover.
## Focus Guidance
Abyss does not control the focus of components on the screen when the Popover is toggled off. To meet
accessibility guidelines, the focus must be set to the previous node when closed. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For example, if a button is pressed to open a popover, focus must return to that button once the popover is closed, so that a screen reader or keyboard user may continue using the app where they left off.
```jsx render
```
```jsx render
```
---
id: popover
category: Layout
title: Popover
description: A popover displays content on top of the page in a separate container and requires user action.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=31310-52671&mode=design&t=Ra4lP896wr2B96P7-0
subDirectory: Popover/v1
---
```jsx
import { Popover } from '@uhg-abyss/mobile';
```
## useState
Pass the value from the `useState` hook to the `isVisible` prop to set the open state of the popover.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
header={
header content
}
footer={}
>
Paragraph copy goes below the title. Copy can be a 100 characters
maximum and expands on no more than four lines
);
};
```
## Title
Use the `title` prop to set the title of the popover. For accessibility purposes, a title is required.
Please provide a title that accurately describes the content of the popover so a screen reader
can provide the description to the user.
A node can be passed in instead of a string but note that accessibility will not be passed in automatically.
Passing in the prop `variant='error'` will change the title to a level 5 heading. The default is a level 3 heading.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [isVisible2, setIsVisible2] = useState(false);
return (
setIsVisible(false)}
footer={}
>
The title should be concise and clear and must not expand on more than 2
lines
);
};
```
## Header
Use the `header` prop to add custom content above the title. Use prop `variant='illustration'` to take up all available space in the header.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
header={
}
footer={
}
>
The header content goes above the title. Here you can add custom content
or replace with an existing Abyss component
);
};
```
## Children
Use the `children` prop to add content below the title. This can include paragraph copy and custom elements. Copy should be no more than 100 characters or four lines of text.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
header={
header content
}
footer={
}
>
Paragraph copy goes below the title. Copy can be a 100 characters
maximum and expands on no more than four lines
}
>
List item one
}
>
List item two is a bit longer
}
>
List item three could even go on two lines
);
};
```
## Footer
Use the `footer` prop to place content at the bottom of the popover. The popover must always have at least one button, so users can close it.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
return (
setIsVisible(false)}
footer={
}
>
Footer buttons stack vertically or horizontally and contain up to three
OS specific buttons in the order that they are placed in the component.
The Popover must always have at least one button, so users can close it
);
};
```
## onClose
Use the `onClose` function to handle the action when close button is triggered or when the background is pressed.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const handleClose = () => {
setIsVisible(false);
console.log('Popover closed');
};
return (
{
setIsVisible(false);
console.log('Popover closed by background tap');
}}
footer={
}
>
Paragraph copy goes below the title. Copy can be a 100 characters
maximum and expands on no more than four lines
);
};
```
### Variants
Available variants: default, error, brand and illustration. The default variant lacks the below modifications, and is automatically applied if no other variant is passed.
- Error: has a serif title, meant for use with the error icon.
- Brand: meant for use with large brand icons, has smaller top header margin.
- Illustration: heading area has no margins to allow for full width images.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [isVisible2, setIsVisible2] = useState(false);
const [isVisible3, setIsVisible3] = useState(false);
return (
setIsVisible(false)}
header={
}
footer={
}
>
In this example the header has no padding or margin on the top and
sides, and reduced margin on the bottom. This allows for full fill
images.
setIsVisible2(false)}
header={}
footer={}
>
Title is set to header 5, and there is increased space between icon and
top in comparison to brand.
setIsVisible3(false)}
header={
}
footer={
}
>
The brand variant is suited to large brand icons.
);
};
```
```jsx render
```
```jsx render
```
## Dynamic Type
To accommodate for larger text sizes, the popover will scroll when it has grown to have a 16px margin on the top and bottom. Depending on the screen size, the height of the popover when scrollable will vary. The footer does not scroll with the rest of the content. Please follow design guidelines when deciding the amount of content to place within popover.
## Focus Guidance
Abyss does not control the focus of components on the screen when the Popover is toggled off. To meet
accessibility guidelines, the focus must be set to the previous node when closed. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For example, if a button is pressed to open a popover, focus must return to that button once the popover is closed, so that a screen reader or keyboard user may continue using the app where they left off.
---
id: progress-bar
category: Data Viz
title: ProgressBar
description: Used to show users the status of loading an app, ongoing processes, saving changes/updates, and more.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=12952%3A84441&t=OIAOmowjKZ4THvqh-0
---
```jsx
import { ProgressBar } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'ProgressBar',
inputs: [
{
prop: 'steps',
type: 'number',
},
{
prop: 'currentStep',
type: 'number',
},
]
}
```
## useState
In this example, we use the `steps` prop to define the number of steps available. React's `useState` hook is used to update the `currentStep` prop.
```jsx live
() => {
const [value, setValue] = useState(0);
const changeValue = (operator) => {
setValue((v) => Math.min(Math.max(v + operator, 0), 10));
};
return (
Current step: {value}/10
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: radio-group
category: Forms
title: RadioGroup
description: A radio input allows people to select only one option from a number of choices. Radio is generally displayed in a radio group.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9596%3A34313&t=FBnhV14SktRX1IuI-0
---
```jsx
import { RadioGroup } from '@uhg-abyss/mobile';
```
### useForm (recommended)
Using the `useForm` hook for handling RadioGroup lets the DOM handle form data.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Form submitted with data:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [radioValue, setRadioValue] = useState('one');
return (
);
};
```
## Label
Use the `label` prop to pass a string as the text next to the radio button.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Children
Content passed to the radio as children will be displayed in place of the label prop. If a value is passed to the label prop in addition to children, the label prop will take priority.
```jsx live
() => {
const form = useForm();
return (
Abyss 1Abyss 2
);
};
```
## Side
Use the `side` prop to place the label text on the left or right side of the radio buttons. By default, the prop is set to `left`, which is the upper example.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## isDisabled
`isDisabled` will disable the radio button. It can be added to either the RadioGroup or the individual Radio components.
```jsx live
() => {
const form = useForm();
return (
Individual radio buttons DisabledAll buttons in component disabled
);
};
```
## hideLabel
The `hideLabel` prop hides the label by each radio button, and is set to `false` by default.
```jsx live
() => {
const [radioValue, setRadioValue] = useState('four');
const [radioValue2, setRadioValue2] = useState('one');
return (
<>
Value = {radioValue}Value = {radioValue2}
>
);
};
```
## shrink
The `shrink` property brings labels and radio buttons closer together than the default. By default, `shrink` prop is set to `false`.
```jsx live
() => {
const form = useForm();
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
RadioButton scales up to 3XL.
```jsx render
```
---
id: rating-v2
category: Data
title: V2Rating
description: Graphical representation of the degree of rating scale.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=10068-35503&mode=design&t=XOrzmaAmfVkUUtDy-0
subDirectory: Rating/v2
sourceIsTS: true
---
```jsx
import { V2Rating } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Rating',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'Large', value: 'large' },
{ label: 'Small', value: 'small' },
{ label: 'Single', value: 'single' },
]
},
{
prop: 'rating',
type: 'string',
},
{
prop: 'reviews',
type: 'number',
},
]
}
```
## Variants
Variant `small` contains the rating to the left side of the populated stars and the number of reviews to the right.
Variant `single` consists of a single star with the rating and reviews in parentheses on the right side.
Variant `large` has a heading style rating value followed by the reviews and stars underneath.
If a variant is not provided it defaults to `small`.
```jsx live
Small
{Array.from({ length: 6 }).map((x, index) => (
))}
Single
{Array.from({ length: 6 }).map((x, index) => (
))}
Large
{Array.from({ length: 6 }).map((x, index) => (
))}
```
## Advanced Layout and Manipulation
`rating` is required and is used to determine the number of active stars as well as the display number. The inputted rating will be formatted to the first decimal point.
The `onPress` prop is optional and will transform the review text into a pressable link.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [activeReviewNum, setActiveReviewNum] = useState('store1');
const reviewNum = [
{ reviews: 5, rating: 5 },
{ reviews: 4, rating: 4 },
{ reviews: 3, rating: 3 },
{ reviews: 2, rating: 2 },
{ reviews: 1, rating: 1 },
];
const handleModal = (reviewNum) => {
setIsVisible(true);
setActiveReviewNum(reviewNum);
return;
};
const ReviewList = (store) => {
return Array.from({ length: activeReviewNum }).map((x, index) => (
}
>
));
};
return (
<>
Small
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Single
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Large
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
}
>
>
);
};
```
## Hide Reviews and Rating
`hideRating` can be used with variant `small` to hide the rating number on the left side.
`hideReviews` can be used with variants `small` and `single` to hide the reviews text.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [activeReviewNum, setActiveReviewNum] = useState('store1');
const reviewNum = [
{ reviews: 5, rating: 5 },
{ reviews: 4, rating: 4 },
{ reviews: 3, rating: 3 },
{ reviews: 2, rating: 2 },
{ reviews: 1, rating: 1 },
];
const handleModal = (reviewNum) => {
setIsVisible(true);
setActiveReviewNum(reviewNum);
return;
};
const ReviewList = (store) => {
return Array.from({ length: activeReviewNum }).map((x, index) => (
}
>
));
};
return (
<>
Hide Rating
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Hide Reviews
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Hide Reviews
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
}
>
>
);
};
```
## With RatingAccumulator
Use with [RatingAccumulator](/mobile/ui/rating-accumulator) for a detailed view of rating data.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: rating
category: Data
title: Rating
description: Graphical representation of the degree of rating scale.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=10068-35503&mode=design&t=XOrzmaAmfVkUUtDy-0
---
```jsx
import { Rating } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Rating',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'Large', value: 'large' },
{ label: 'Small', value: 'small' },
{ label: 'Single', value: 'single' },
]
},
{
prop: 'rating',
type: 'string',
},
{
prop: 'reviews',
type: 'number',
},
]
}
```
## Variants
Variant `small` contains the rating to the left side of the populated stars and the number of reviews to the right.
Variant `single` consists of a single star with the rating value to the right and review count in parentheses.
Variant `large` has only a visual rating of 0-5 populated stars.
```jsx live
Small
{Array.from({ length: 6 }).map((x, index) => (
))}
Single
{Array.from({ length: 6 }).map((x, index) => (
))}
Large
{Array.from({ length: 6 }).map((x, index) => (
))}
```
## Advanced Layout and Manipulation
`rating` is required and is used to determine the number of active stars as well as the display number. The inputted rating will be formatted to the first decimal point.
`hideRating` can be used with variant `small` to hide the rating number on the left side.
The `onPress` prop is optional and will transform the review text for variant `small` and `single` into a pressable link.
```jsx live
() => {
const [isVisible, setIsVisible] = useState(false);
const [activeReviewNum, setActiveReviewNum] = useState('store1');
const reviewNum = [
{ reviews: 5, rating: 5 },
{ reviews: 4, rating: 4 },
{ reviews: 3, rating: 3 },
{ reviews: 2, rating: 2 },
{ reviews: 1, rating: 1 },
];
const handleModal = (reviewNum) => {
setIsVisible(true);
setActiveReviewNum(reviewNum);
return;
};
const ReviewList = (store) => {
return Array.from({ length: activeReviewNum }).map((x, index) => (
}
>
));
};
return (
<>
Small
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Single
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
Hide Rating
{Array.from({ length: 5 }).map((x, index) => (
handleModal(reviewNum[index].reviews)}
/>
))}
}
>
>
);
};
```
```jsx render
```
```jsx render
```
---
id: rating-accumulator
category: Data Viz
title: RatingAccumulator
description: A visual representation of rating distribution using horizontal bars.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=10068-35503&mode=design&t=XOrzmaAmfVkUUtDy-0
sourceIsTS: true
---
```jsx
import { RatingAccumulator } from '@uhg-abyss/mobile';
```
## Data
The `data` prop is an array of numbers representing percentages for each star rating level, from 1 stars (index 0) to 5 stars (index 4).
```jsx live
```
## Alternate Theme
The `alt` prop changes the color theme to an alternate style, useful for displaying against darker backgrounds.
```jsx live
```
```jsx render
```
```jsx render
```
```jsx render
```
Due to React Native limitations, this component enables keyboard access despite not having an interactive element. This component requires an accessibility label for use with a screen reader, which enables keyboard focus.
```jsx render
```
---
id: scroll-wheel
category: Controls
title: ScrollWheel
description: A scrollable list of distinct values that allow selection between several options.
---
```jsx sandbox
{
component: 'ScrollWheel',
}
() => {
const [index, setIndex] = useState(0);
const options = [1, 2, 3, 4, 5, 6];
return (
)
}
```
## Usage
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [index, setIndex] = useState(1);
const options = [1, 2, 3, 4, 5, 6];
return (
You have Selected: {options[index]}
);
};
```
## Options
Use the `options` prop to set the options to be displayed on the scroll wheel. The `options` prop accepts an array
of strings and is a required prop.
```jsx live
() => {
const [index, setIndex] = useState(1);
const options = ['Kendall', 'Reagan', 'Nathan', 'Morgan', 'Billy'];
return (
You have selected: {options[index]}
);
};
```
## Colors
Use the `activeColor` prop to set the color of the selected option's text. In addition, use the
`indicatorColor` prop to set the background color of the selected indicator.
```jsx live
() => {
const [index, setIndex] = useState(1);
const options = [1, 2, 3, 4, 5, 6];
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: search-bar
category: Forms
title: SearchBar
description: Provides an input field for searching content within an app to find specific items.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=35761-15587&mode=design&t=5prUNtGYxFI7SAco-0
---
```jsx
import { SearchBar } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'SearchBar',
}
() => {
const form = useForm();
return (
);
};
```
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook sets state for the component.
```jsx live
() => {
const [text, setText] = useState('');
const handleSubmit = () => {
console.log('Submitted:', text);
};
return (
);
};
```
## Placeholder
The `placeholder` prop gives users a short description in the search bar before they enter a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Submit
The `onSubmit` prop fires a callback when the submit action is triggered.
The value will be passed in as a parameter.
```jsx live
() => {
const [text, setText] = useState('');
const handleSubmit = (val) => {
console.log(val);
};
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
Similar to all other components used within [AppBar](/mobile/ui/app-bar), SearchBar will scale up to 3XL.
---
id: search-input
category: Forms
title: SearchInput
description: A type of input field that allows searching through content.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=41039-16146&mode=design&t=bfPqTvn7mEdSo5pn-0
---
```jsx
import { SearchInput } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'SearchInput',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'helpContent',
type: 'string',
},
],
}
() => {
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
const [value, setValue] = React.useState('');
const [results, setResults] = useState([]);
const handleSubmit = ()=>{
console.log(results)
}
return (
);
};
```
## useState
Using the `useState` hook sets state for the component.
```jsx live
() => {
const [text, setText] = useState('');
const handleSubmit = () => {
console.log('Submitted:', text);
};
return (
);
};
```
## onChange
The `onChange` prop handles the action for the search results.
```jsx live
() => {
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
const [value, setValue] = React.useState('');
const [results, setResults] = useState([]);
return (
);
};
```
## Fuse.js
Search Input filtering uses the Fuse.js library to fuzzy filter results. What is fuzzy searching? Generally speaking, fuzzy searching (more formally known as approximate string matching) is the technique of finding strings that are approximately equal to a given pattern (rather than exactly).
### Fuse Configurations
To adjust the fuse configurations, pass the desired options into the `fuseConfigs` prop. Note that `keys` is required when using fuse. By default the fuse search configurations are:
```
{
includeMatches: true,
findAllMatches: true,
threshold: 0,
ignoreLocation: true,
minMatchCharLength: searchText.length,
keys,
}
```
The default configurations return the search results object below:
```
{
item: []
}
```
### Fuse Data
The `options` prop is the information that fuse will filter on and display in the search dropdown. You can search on any value(s) in the object, see Fuse Keys below. Required when using fuse.
```jsx live
() => {
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
const [value, setValue] = React.useState('');
const [results, setResults] = useState([]);
const ResultsList = styled('ScrollView', {
height: 200,
});
return (
Results:
{(value.length > 0 ? results : data).map((item, i) => {
return ;
})}
);
};
```
### Fuse Keys
List of keys that will be searched. This supports nested paths, weighted search, searching in arrays of objects. Required when using fuse. Below the `keys` set are "label" and "value".
```jsx live
() => {
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
const [text, setText] = useState('');
const [results, setResults] = useState([]);
const ResultsList = styled('ScrollView', {
height: 200,
});
return (
Results:
{(text.length > 0 ? results : data).map((item, i) => {
return ;
})}
);
};
```
## Custom Filtering
Use the `customFilter` prop to override the fuse.js filtering. In the example function below, the filter is checking the first letter typed in the search bar against the first letter of each item in the list. If the letter is a match the item is included in the filtered list.
```jsx live
() => {
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
const [results, setResults] = useState([]);
const [text, setText] = useState('');
const ResultsList = styled('ScrollView', {
height: 200,
});
const filterFunction = (searchText, list) => {
const newList = [];
if (searchText.length > 0) {
list.forEach((item) => {
const title = item.label.toUpperCase();
if (title[0] === searchText[0].toUpperCase()) {
newList.push(item);
}
});
}
return newList;
};
return (
Results:
{(text.length > 0 ? results : data).map((item, i) => {
return ;
})}
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: search-input-button
category: Navigation
title: SearchInputButton
description: Acts as a placeholder for search bar.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=9600-35750&mode=design&t=9miNk11OVJWfR3kX-0
---
```jsx
import { SearchInputButton } from '@uhg-abyss/mobile';
```
## Placeholder
The `placeholder` prop gives users a short description in the search bar.
```jsx live
() => {
return ;
};
```
## onPress
Use the `onPress` prop to determine the action when the search button is pressed.
```jsx live
() => {
const handlePress = () => {
console.log('pressed');
};
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: segmented-controls
category: Forms
title: SegmentedControls
description: A segmented control is a linear set of two or more segments, each of which functions as a button. There cannot be more than one segment selected, so under the hood this behaves like a radio group.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9553%3A32917&t=lY6iM2O8OTPyLv8A-0
---
```jsx
import { SegmentedControls } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'SegmentedControls',
inputs: [
{
prop: 'shrink',
type: 'boolean',
},
]
}
() => {
const form = useForm({
defaultValues: {
'segmented-controls-sandbox': 'one',
},
});
return (
);
};
```
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm({
defaultValues: {
'segmented-controls-form': 'one',
},
});
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [activeValue, setActiveValue] = useState('one');
const handleSubmit = () => {
console.log('Submitted:', activeValue);
};
return (
);
};
```
## Label
The `label` prop is used to define the display in each Tab. The `label` can be an Icon or text.
```jsx live
() => {
const form = useForm({
defaultValues: {
'segmented-controls-label': 'one',
'segmented-controls-label-icons': 'two',
},
});
return (
}
value="one"
/>
}
value="two"
/>
}
value="three"
/>
);
};
```
## Structure
Segmented controls consist of a parent element and several children. The parent element `` handles the active Tab state.
While the children define the segments of the component.
Each child is a Tab: `` A new child is required for every segment.
```jsx live
() => {
const form = useForm({
defaultValues: {
'segmented-controls-structure': 'snow',
},
});
return (
);
};
```
## Shrink
The `shrink` prop toggles whether the component will take up the full width of the parent container. When true, they will automatically size based on the number of tabs and their content. Defaults to `false`.
```jsx live
() => {
const form = useForm({
defaultValues: {
'segmented-controls-one': 'snow',
'segmented-controls-two': 'clouds',
'segmented-controls-three': 'sun',
},
});
return (
);
};
```
## Example
```jsx live
() => {
const [activeTab, setActiveTab] = useState('one');
return (
Title {activeTab}
);
};
```
## Dynamic Type
SegmentedControls scale to 3XL. Any icons passed to the label prop will need to set `maxFontSizeMultiplier={1.3}`.
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: select-input-v2
category: Forms
title: V2SelectInput
description: Allows users to select one value from a provided list of options.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=18828-105743&mode=design&t=Aa48cFkeiLakVzb1-0
---
```jsx
import { V2SelectInput } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2SelectInput',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isRequired',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
],
}
() => {
const form = useForm();
return (
);
};
```
## Usage
Use the `options` prop to supply the options that can be selected. `options` is an array of objects, where each object should have two properties:
- `label`, a string which is how the option will be displayed in the list
- `value`, a string which is the unique identifier for the option
Sections can also be specified, in which case the section object should have `title` and `items` properties instead of `label` and `value` (See [Titles](#titles) for more details).
```
options = {
[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2', isDisabled: true },
{ label: 'Item 3', value: 'item3' },
{ label: 'Item 4', value: 'item4' },
{ label: 'Item 5', value: 'item5' },
]
}
```
## useForm (recommended)
Use the `useForm` hook to manage the state of the select input. The `model` prop should be set to a unique string that identifies the form field.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [selection, setSelection] = useState();
return (
);
};
```
## Titles
To create sections in the list, pass objects into the `options` array that have the `title` and `items` properties. `title` specifies the name of the title, which will be bolded and not selectable, `items` should contain the options within that section (with the same `label`/`value` format as normal).
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Label
Use the `label` prop to display a label above the input menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Required
Use the `isRequired` prop to display an asterisk next to the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Hint Text
Use the `hintText` prop to display text below the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
options={[
{ label: 'item 1', value: 'item11' },
{ label: 'item 2', value: 'item12' },
{ label: 'item 3', value: 'item13' },
]}
/>
);
};
```
## Messages
Use the `errorMessage` and `successMessage` props to display a custom error or success message below the menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the select list input field so users cannot select a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disable Option Items
Disable an individual option item by setting the `isDisabled` key to `true` within the object.
```jsx live
() => {
const form = useForm();
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: select-input
category: Forms
title: SelectInput
description: Allows users to select one value from a provided list of options.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=18828-105743&mode=design&t=Aa48cFkeiLakVzb1-0
---
```jsx
import { SelectInput } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'SelectInput',
inputs: [
{
prop: 'label',
type: 'string',
defaultValue: 'Sandbox',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isRequired',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
],
}
() => {
const form = useForm();
return (
);
};
```
## Usage
Use the `options` prop to supply the options that can be selected. `options` is an array of objects, where each object should have two properties:
- `label`, a string which is how the option will be displayed in the list
- `value`, a string which is the unique identifier for the option
Sections can also be specified, in which case the section object should have `title` and `items` properties instead of `label` and `value` (See [Titles](#titles) for more details).
```
options = {
[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2', isDisabled: true },
{ label: 'Item 3', value: 'item3' },
{ label: 'Item 4', value: 'item4' },
{ label: 'Item 5', value: 'item5' },
]
}
```
## useForm (recommended)
Use the `useForm` hook to manage the state of the select input. The `model` prop should be set to a unique string that identifies the form field.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [selection, setSelection] = useState();
return (
);
};
```
## Titles
To create sections in the list, pass objects into the `options` array that have the `title` and `items` properties. `title` specifies the name of the title, which will be bolded and not selectable, `items` should contain the options within that section (with the same `label`/`value` format as normal).
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Label
Use the `label` prop to display a label above the input menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Required
Use the `isRequired` prop to display an asterisk next to the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Hint Text
Use the `hintText` prop to display text below the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
options={[
{ label: 'item 1', value: 'item11' },
{ label: 'item 2', value: 'item12' },
{ label: 'item 3', value: 'item13' },
]}
/>
);
};
```
## Messages
Use the `errorMessage` and `successMessage` props to display a custom error or success message below the menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the select list input field so users cannot select a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disable Option Items
Disable an individual option item by setting the `isDisabled` key to `true` within the object.
```jsx live
() => {
const form = useForm();
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: select-input-multi-v2
category: Forms
title: V2SelectInputMulti
description: Allows users to select multiple values from a provided list of options.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=18828-105743&mode=design&t=Aa48cFkeiLakVzb1-0
---
```jsx
import { V2SelectInputMulti } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2SelectInputMulti',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isSearchable',
type: 'boolean',
},
{
prop: 'selectAll',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
],
}
() => {
const form = useForm();
return (
);
};
```
## Usage
Use the `options` prop to supply the options that can be selected. `options` is an array of objects, where each object should have two properties:
- `label`, a string which is how the option will be displayed in the list
- `value`, a string which is the unique identifier for the option
Sections can also be specified, in which case the section object should have `title`, `value`, and `items` properties instead of `label` and `value` (See [Titles](#titles) for more details).
```
options = {
[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2', isDisabled: true },
{ label: 'Item 3', value: 'item3' },
{ label: 'Item 4', value: 'item4' },
{ label: 'Item 5', value: 'item5' },
]
}
```
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm();
const options = [
{ label: 'Colors', value: 'Colors' },
{ label: 'Elevation', value: 'E' },
{ label: 'Icon Brand', value: 'IB' },
{ label: 'Typography', value: 'T' },
{
title: 'CTA',
value: 'CTA',
items: [
{ label: 'Button', value: 'button' },
{ label: 'Cell Group', value: 'cellGroup' },
{ label: 'Chip', value: 'chip' },
],
},
{
title: 'Controls',
value: 'Controls',
items: [
{ label: 'Checkbox', value: 'checkbox' },
{ label: 'Checkbox Group', value: 'CG' },
{ label: 'Radio Group', value: 'RG' },
{ label: 'Segmented Controls', value: 'SC' },
{ label: 'Toggle Switch', value: 'TS' },
],
},
{
title: 'Data',
value: 'Title1',
items: [
{ label: 'Avatar', value: 'avatar' },
{ label: 'Indicator', value: 'indicator' },
{ label: 'Progress Bar', value: 'PB' },
],
},
{
title: 'Data Viz',
value: 'DataViz',
items: [
{ label: 'Accordion', value: 'accordion' },
{ label: 'Accumulator', value: 'accumulator' },
{ label: 'Donut Chart', value: 'DC' },
],
},
{
title: 'Forms',
value: 'Forms',
items: [
{ label: 'Date Input', value: 'DI' },
{ label: 'Select Input', value: 'SI' },
{ label: 'Select Input Multi', value: 'SIM' },
{ label: 'Text Input', value: 'TI' },
],
},
{
title: 'Layout',
value: 'Layout',
items: [
{ label: 'Bottom Sheet', value: 'BS' },
{ label: 'Modal', value: 'modal' },
{ label: 'Card', value: 'card' },
],
},
{
title: 'Media',
value: 'Media',
items: [
{ label: 'Icon', value: 'icon' },
{ label: 'Icon Custom', value: 'IC' },
{ label: 'Icon Material', value: 'IM' },
],
},
{
title: 'Navigation',
value: 'nav',
items: [
{ label: 'Link', value: 'link' },
{ label: 'Tabs', value: 'tabs' },
],
},
{
title: 'Notifications',
value: 'Notifications',
items: [
{ label: 'Alert', value: 'alert' },
{ label: 'Badge', value: 'badge' },
{ label: 'FAB', value: 'fab' },
{ label: 'Toast', value: 'toast' },
],
},
{
title: 'Providers',
value: 'providers',
items: [{ label: 'LagoonProvider', value: 'LP' }],
},
{
title: 'Typography',
value: 'typography',
items: [
{ label: 'Heading', value: 'heading' },
{ label: 'Text', value: 'text' },
],
},
];
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const options = [
{ label: 'Colors', value: 'Colors' },
{ label: 'Elevation', value: 'E' },
{ label: 'Icon Brand', value: 'IB' },
{ label: 'Typography', value: 'T' },
{
title: 'CTA',
value: 'CTA',
items: [
{ label: 'Button', value: 'button' },
{ label: 'Cell Group', value: 'cellGroup' },
{ label: 'Chip', value: 'chip' },
],
},
{
title: 'Controls',
value: 'Controls',
items: [
{ label: 'Checkbox', value: 'checkbox' },
{ label: 'Checkbox Group', value: 'CG' },
{ label: 'Radio Group', value: 'RG' },
{ label: 'Segmented Controls', value: 'SC' },
{ label: 'Toggle Switch', value: 'TS' },
],
},
{
title: 'Data',
value: 'Title1',
items: [
{ label: 'Avatar', value: 'avatar' },
{ label: 'Indicator', value: 'indicator' },
{ label: 'Progress Bar', value: 'PB' },
],
},
{
title: 'Data Viz',
value: 'DataViz',
items: [
{ label: 'Accordion', value: 'accordion' },
{ label: 'Accumulator', value: 'accumulator' },
{ label: 'Donut Chart', value: 'DC' },
],
},
{
title: 'Forms',
value: 'Forms',
items: [
{ label: 'Date Input', value: 'DI' },
{ label: 'Select Input', value: 'SI' },
{ label: 'Select Input Multi', value: 'SIM' },
{ label: 'Text Input', value: 'TI' },
],
},
{
title: 'Layout',
value: 'Layout',
items: [
{ label: 'Bottom Sheet', value: 'BS' },
{ label: 'Modal', value: 'modal' },
{ label: 'Card', value: 'card' },
],
},
{
title: 'Media',
value: 'Media',
items: [
{ label: 'Icon', value: 'icon' },
{ label: 'Icon Custom', value: 'IC' },
{ label: 'Icon Material', value: 'IM' },
],
},
{
title: 'Navigation',
value: 'nav',
items: [
{ label: 'Link', value: 'link' },
{ label: 'Tabs', value: 'tabs' },
],
},
{
title: 'Notifications',
value: 'Notifications',
items: [
{ label: 'Alert', value: 'alert' },
{ label: 'Badge', value: 'badge' },
{ label: 'FAB', value: 'fab' },
{ label: 'Toast', value: 'toast' },
],
},
{
title: 'Providers',
value: 'providers',
items: [{ label: 'LagoonProvider', value: 'LP' }],
},
{
title: 'Typography',
value: 'typography',
items: [
{ label: 'Heading', value: 'heading' },
{ label: 'Text', value: 'text' },
],
},
];
const [value, setValue] = useState([]);
const handleSubmit = () => {
console.log('Submitted:', value);
};
return (
);
};
```
## Titles
To create sections in the list, pass objects into the `options` array that have the `title`, `value`, and `items` properties. `title` specifies the name of the title, which will be bolded and not selectable, `value` is the unique identifier for the title, while `items` should contain the options within that section (with the same `label`/`value` format as normal).
```
options = {
[
{
title: 'Title 1',
value: 'Title1',
items: [
{ label: 'item 1', value: 'item11' },
{ label: 'item 2', value: 'item12', isDisabled: true },
{ label: 'item 3', value: 'item13' },
],
},
]
}
```
## Label
Use the `label` prop to display a label above the input menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Required
Use the `isRequired` prop to display an asterisk next to the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Hint Text
Use the `hintText` prop to display text below the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
options={[
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
]}
/>
);
};
```
## Messages
Use the `errorMessage` and `successMessage` props to display a custom error or success message below the menu.
```jsx live
() => {
const form = useForm();
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the select list input field so users cannot select a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disable Option Items
Disable an individual option item by setting the `isDisabled` key to `true` within the object.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Select All
By setting the `selectAll` property to `true` you can make a "Select All" option visible at the top of the dropdown. When selected, all options will be selected. When deselected, all options will be deselected.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Searchable
Use the `isSearchable` prop to display an input field for the user to search/filter the list of options that is located inside the dropdown.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Fuse.js
Search Bar filtering uses the Fuse.js library to fuzzy filter results. What is fuzzy searching? Generally speaking, fuzzy searching (more formally known as approximate string matching) is the technique of finding strings that are approximately equal to a given pattern (rather than exactly).
### Fuse Data
The `options` prop is the information that fuse will filter on and display in the search dropdown.
### Fuse Configurations
The fuse search options are set by default as follows. The keys are set to `label` and cannot be changed.
```
{
keys: ['label', 'items.label'],
includeMatches: true,
findAllMatches: true,
threshold: 0,
ignoreLocation: true,
minMatchCharLength: searchText.length,
}
```
### Custom Fuse Configurations
You can customize the fuse filter by following the documentation on Fuse and passing your configurations into the `fuseConfigs` prop. To get the filtered list back, be sure `includeMatches` is always set to `true`.
```jsx live
() => {
const [value, setValue] = useState([]);
const customFuseConfigs = {
ignoreLocation: false,
distance: 0,
includeMatches: true,
};
return (
);
};
```
## Custom Filtering
Use the `customFilter` prop to override the fuse.js filtering. The results returned from your customFilter function should be passed into the options prop. In the example function below, the filter is checking the first letter typed in the search bar against the first letter of each item in the list. If the letter is a match the item is included in the filtered list. Any 'type-ahead' styles will not be applied when a custom filtering function is being used.
```jsx live
() => {
const [value, setValue] = useState([]);
const filterFunction = (searchText, list) => {
const newList = [];
if (searchText.length > 0) {
list.forEach((item) => {
if (item.label) {
if (item.label[0].toUpperCase() == searchText[0].toUpperCase()) {
newList.push(item);
}
}
if (item.items) {
item.items.forEach((i) => {
if (i.label[0].toUpperCase() == searchText[0].toUpperCase()) {
newList.push(i);
}
});
}
});
}
return newList;
};
return (
);
};
```
## Notes
In order for a user to select an item from the menu while the softkeyboard is up, the prop `keyboardShouldPersistTaps` is set to `'always'`. If the menu is contained in a ScrollView, `keyboardShouldPersistTaps={'always'}` should be set with in that view. This allows for the keyboard to remain open and an item to be selected on initial tap.
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: select-input-multi
category: Forms
title: SelectInputMulti
description: Allows users to select multiple values from a provided list of options.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=18828-105743&mode=design&t=Aa48cFkeiLakVzb1-0
---
```jsx
import { SelectInputMulti } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'SelectInputMulti',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'isSearchable',
type: 'boolean',
},
{
prop: 'selectAll',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
],
}
() => {
const form = useForm();
return (
);
};
```
## Usage
Use the `options` prop to supply the options that can be selected. `options` is an array of objects, where each object should have two properties:
- `label`, a string which is how the option will be displayed in the list
- `value`, a string which is the unique identifier for the option
Sections can also be specified, in which case the section object should have `title`, `value`, and `items` properties instead of `label` and `value` (See [Titles](#titles) for more details).
```
options = {
[
{ label: 'Item 1', value: 'item1' },
{ label: 'Item 2', value: 'item2', isDisabled: true },
{ label: 'Item 3', value: 'item3' },
{ label: 'Item 4', value: 'item4' },
{ label: 'Item 5', value: 'item5' },
]
}
```
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm();
const options = [
{ label: 'Colors', value: 'Colors' },
{ label: 'Elevation', value: 'E' },
{ label: 'Icon Brand', value: 'IB' },
{ label: 'Typography', value: 'T' },
{
title: 'CTA',
value: 'CTA',
items: [
{ label: 'Button', value: 'button' },
{ label: 'Cell Group', value: 'cellGroup' },
{ label: 'Chip', value: 'chip' },
],
},
{
title: 'Controls',
value: 'Controls',
items: [
{ label: 'Checkbox', value: 'checkbox' },
{ label: 'Checkbox Group', value: 'CG' },
{ label: 'Radio Group', value: 'RG' },
{ label: 'Segmented Controls', value: 'SC' },
{ label: 'Toggle Switch', value: 'TS' },
],
},
{
title: 'Data',
value: 'Title1',
items: [
{ label: 'Avatar', value: 'avatar' },
{ label: 'Indicator', value: 'indicator' },
{ label: 'Progress Bar', value: 'PB' },
],
},
{
title: 'Data Viz',
value: 'DataViz',
items: [
{ label: 'Accordion', value: 'accordion' },
{ label: 'Accumulator', value: 'accumulator' },
{ label: 'Donut Chart', value: 'DC' },
],
},
{
title: 'Forms',
value: 'Forms',
items: [
{ label: 'Date Input', value: 'DI' },
{ label: 'Select Input', value: 'SI' },
{ label: 'Select Input Multi', value: 'SIM' },
{ label: 'Text Input', value: 'TI' },
],
},
{
title: 'Layout',
value: 'Layout',
items: [
{ label: 'Bottom Sheet', value: 'BS' },
{ label: 'Modal', value: 'modal' },
{ label: 'Card', value: 'card' },
],
},
{
title: 'Media',
value: 'Media',
items: [
{ label: 'Icon', value: 'icon' },
{ label: 'Icon Custom', value: 'IC' },
{ label: 'Icon Material', value: 'IM' },
],
},
{
title: 'Navigation',
value: 'nav',
items: [
{ label: 'Link', value: 'link' },
{ label: 'Tabs', value: 'tabs' },
],
},
{
title: 'Notifications',
value: 'Notifications',
items: [
{ label: 'Alert', value: 'alert' },
{ label: 'Badge', value: 'badge' },
{ label: 'FAB', value: 'fab' },
{ label: 'Toast', value: 'toast' },
],
},
{
title: 'Providers',
value: 'providers',
items: [{ label: 'LagoonProvider', value: 'LP' }],
},
{
title: 'Typography',
value: 'typography',
items: [
{ label: 'Heading', value: 'heading' },
{ label: 'Text', value: 'text' },
],
},
];
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const options = [
{ label: 'Colors', value: 'Colors' },
{ label: 'Elevation', value: 'E' },
{ label: 'Icon Brand', value: 'IB' },
{ label: 'Typography', value: 'T' },
{
title: 'CTA',
value: 'CTA',
items: [
{ label: 'Button', value: 'button' },
{ label: 'Cell Group', value: 'cellGroup' },
{ label: 'Chip', value: 'chip' },
],
},
{
title: 'Controls',
value: 'Controls',
items: [
{ label: 'Checkbox', value: 'checkbox' },
{ label: 'Checkbox Group', value: 'CG' },
{ label: 'Radio Group', value: 'RG' },
{ label: 'Segmented Controls', value: 'SC' },
{ label: 'Toggle Switch', value: 'TS' },
],
},
{
title: 'Data',
value: 'Title1',
items: [
{ label: 'Avatar', value: 'avatar' },
{ label: 'Indicator', value: 'indicator' },
{ label: 'Progress Bar', value: 'PB' },
],
},
{
title: 'Data Viz',
value: 'DataViz',
items: [
{ label: 'Accordion', value: 'accordion' },
{ label: 'Accumulator', value: 'accumulator' },
{ label: 'Donut Chart', value: 'DC' },
],
},
{
title: 'Forms',
value: 'Forms',
items: [
{ label: 'Date Input', value: 'DI' },
{ label: 'Select Input', value: 'SI' },
{ label: 'Select Input Multi', value: 'SIM' },
{ label: 'Text Input', value: 'TI' },
],
},
{
title: 'Layout',
value: 'Layout',
items: [
{ label: 'Bottom Sheet', value: 'BS' },
{ label: 'Modal', value: 'modal' },
{ label: 'Card', value: 'card' },
],
},
{
title: 'Media',
value: 'Media',
items: [
{ label: 'Icon', value: 'icon' },
{ label: 'Icon Custom', value: 'IC' },
{ label: 'Icon Material', value: 'IM' },
],
},
{
title: 'Navigation',
value: 'nav',
items: [
{ label: 'Link', value: 'link' },
{ label: 'Tabs', value: 'tabs' },
],
},
{
title: 'Notifications',
value: 'Notifications',
items: [
{ label: 'Alert', value: 'alert' },
{ label: 'Badge', value: 'badge' },
{ label: 'FAB', value: 'fab' },
{ label: 'Toast', value: 'toast' },
],
},
{
title: 'Providers',
value: 'providers',
items: [{ label: 'LagoonProvider', value: 'LP' }],
},
{
title: 'Typography',
value: 'typography',
items: [
{ label: 'Heading', value: 'heading' },
{ label: 'Text', value: 'text' },
],
},
];
const [value, setValue] = useState([]);
const handleSubmit = () => {
console.log('Submitted:', value);
};
return (
);
};
```
## Titles
To create sections in the list, pass objects into the `options` array that have the `title`, `value`, and `items` properties. `title` specifies the name of the title, which will be bolded and not selectable, `value` is the unique identifier for the title, while `items` should contain the options within that section (with the same `label`/`value` format as normal).
```
options = {
[
{
title: 'Title 1',
value: 'Title1',
items: [
{ label: 'item 1', value: 'item11' },
{ label: 'item 2', value: 'item12', isDisabled: true },
{ label: 'item 3', value: 'item13' },
],
},
]
}
```
## Label
Use the `label` prop to display a label above the input menu.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Required
Use the `isRequired` prop to display an asterisk next to the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Hint Text
Use the `hintText` prop to display text below the label.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
options={[
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
]}
/>
);
};
```
## Messages
Use the `errorMessage` and `successMessage` props to display a custom error or success message below the menu.
```jsx live
() => {
const form = useForm();
const data = [
{ value: 'react', label: 'React' },
{ value: 'ng', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'vue', label: 'Vue' },
{ value: 'alpine', label: 'Alpine' },
{ value: 'ember', label: 'Ember' },
{ value: 'stimulus', label: 'Stimulus' },
{ value: 'preact', label: 'Preact' },
];
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the select list input field so users cannot select a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disable Option Items
Disable an individual option item by setting the `isDisabled` key to `true` within the object.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Select All
By setting the `selectAll` property to `true` you can make a "Select All" option visible at the top of the dropdown. When selected, all options will be selected. When deselected, all options will be deselected.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Searchable
Use the `isSearchable` prop to display an input field for the user to search/filter the list of options that is located inside the dropdown.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Fuse.js
Search Bar filtering uses the Fuse.js library to fuzzy filter results. What is fuzzy searching? Generally speaking, fuzzy searching (more formally known as approximate string matching) is the technique of finding strings that are approximately equal to a given pattern (rather than exactly).
### Fuse Data
The `options` prop is the information that fuse will filter on and display in the search dropdown.
### Fuse Configurations
The fuse search options are set by default as follows. The keys are set to `label` and cannot be changed.
```
{
keys: ['label', 'items.label'],
includeMatches: true,
findAllMatches: true,
threshold: 0,
ignoreLocation: true,
minMatchCharLength: searchText.length,
}
```
### Custom Fuse Configurations
You can customize the fuse filter by following the documentation on Fuse and passing your configurations into the `fuseConfigs` prop. To get the filtered list back, be sure `includeMatches` is always set to `true`.
```jsx live
() => {
const [value, setValue] = useState([]);
const customFuseConfigs = {
ignoreLocation: false,
distance: 0,
includeMatches: true,
};
return (
);
};
```
## Custom Filtering
Use the `customFilter` prop to override the fuse.js filtering. The results returned from your customFilter function should be passed into the options prop. In the example function below, the filter is checking the first letter typed in the search bar against the first letter of each item in the list. If the letter is a match the item is included in the filtered list. Any 'type-ahead' styles will not be applied when a custom filtering function is being used.
```jsx live
() => {
const [value, setValue] = useState([]);
const filterFunction = (searchText, list) => {
const newList = [];
if (searchText.length > 0) {
list.forEach((item) => {
if (item.label) {
if (item.label[0].toUpperCase() == searchText[0].toUpperCase()) {
newList.push(item);
}
}
if (item.items) {
item.items.forEach((i) => {
if (i.label[0].toUpperCase() == searchText[0].toUpperCase()) {
newList.push(i);
}
});
}
});
}
return newList;
};
return (
);
};
```
## Notes
In order for a user to select an item from the menu while the softkeyboard is up, the prop `keyboardShouldPersistTaps` is set to `'always'`. If the menu is contained in a ScrollView, `keyboardShouldPersistTaps={'always'}` should be set with in that view. This allows for the keyboard to remain open and an item to be selected on initial tap.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: skeleton-v2
category: Overlay
title: V2Skeleton
description: Placeholder for loading content.
design: https://www.figma.com/design/5djnh49w0SBYAG5tFJifIG/v1.66.0-App-Abyss-Global%E2%80%A8Component-Library?m=auto&node-id=1469-39887&t=og176wcAIBNmTzwi-1
sourceIsTS: true
subDirectory: Skeleton/v2
---
```jsx
import { V2Skeleton } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Skeleton',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'Text', value: 'text' },
{ label: 'Square', value: 'square' },
{ label: 'Round', value: 'round' },
],
},
{
prop: 'height',
type: 'string',
},
{
prop: 'width',
type: 'string',
},
{
prop: 'animated',
type: 'boolean'
},
],
}
```
## Usage
The `Skeleton` component is a placeholder for content that is loading. It helps convey to users that the page is functioning as intended and that content will appear shortly.
###### Common Use Cases:
- Displaying a loading state for text, images, or cards.
- Providing a visual cue for asynchronous content.
- Maintaining layout consistency while data is being fetched.
```jsx live
() => {
const avatar =
'https://abyss.uhc.com/img/team/AbyssMobile/Thomas-Musengwa.png';
const cardImage = 'https://abyss.uhc.com/img/graphics/card-image-example.png';
const [isDoneLoading, onToggle] = useToggle(false);
const returnContent = () => {
if (isDoneLoading) {
return (
<>
Name goes hereDescription
>
);
}
return null;
};
const returnSkeletonStack = () => {
if (!isDoneLoading) {
return (
);
}
return null;
};
return (
{returnContent()}
{returnSkeletonStack()}
);
};
```
## Width and Height
The `height` and `width` props define the dimensions of the component. Setting their values to `100%` will fill its parent container.
The default values for `height` and `width` depend on the variant. For more details, refer to the [Variant](#variant) section.
```jsx live
() => {
return (
);
};
```
## Variant & Alt
The `alt` prop adjusts the color of the component, changing it to a lighter shade.
The `variant` prop defines the default size and border radius of the component. Use this prop to match the skeleton's shape to the content it represents.
###### Available Variants:
- **`text`**: The default variant with a `height` of _20px_, a `width` of _180px_, and slightly rounded edges. Ideal for text blocks.
- **`square`**: This variant has a default `height` and `width` of _48px_, with slightly rounded edges. Suitable for square images or icons.
- **`round`**: This variant also has a default `height` and `width` of _48px_, but features fully rounded edges. Best for avatars or circular icons.
```jsx live
() => {
const SkeletonGroup = styled(Layout.Group, {
padding: 8,
variants: {
alt: { true: { backgroundColor: '$gray3' } },
},
});
return (
);
};
```
## Animations & Color
Animation is enabled by default. To disable it, set the `animated` prop to `false`.
The `color` prop can be used to customize the color of the component.
You can also customize the loader's color and opacity using the `loaderColor` and `loaderOpacity` props.
```jsx live
() => {
const [isAnimated, onToggle] = useToggle(true);
return (
);
};
```
## Skeleton with Children
Add children to the `Skeleton` component by placing elements between the `Skeleton` tags.
```jsx live
() => {
const Row = styled('View', {
display: 'flex',
flexDirection: 'row',
marginVertical: 15,
});
const InnerWrapper = styled('View', {
padding: '$md',
justifyContent: 'space-between',
height: '100%',
});
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
Component Tokens
**Note:** Click on the tokens to copy onto your clipboard.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: skeleton
category: Overlay
title: Skeleton
description: Placeholder for loading content.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=12865-62521
---
```jsx
import { Skeleton } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Skeleton',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'rectangular', value: 'rectangular' },
{ label: 'rounded', value: 'rounded' },
{ label: 'circular', value: 'circular' },
],
},
{
prop: 'height',
type: 'string',
},
{
prop: 'width',
type: 'string',
},
{
prop: 'animated',
type: 'boolean'
},
],
}
```
## Usage
`Skeleton` is a placeholder component for content that is loading. `Skeleton` can help convey to users that content is on its way and the page is functioning as intended.
```jsx live
() => {
const avatar = 'https://abyss.uhc.com/img/team/scott-houser.jpg';
const cardImage = 'https://abyss.uhc.com/img/graphics/card-image-example.png';
const { isOpen: isDoneLoading, onToggle } = Web.useToggle();
const returnContent = () => {
if (isDoneLoading) {
return (
<>
profile has loadedName goes hereDescription
>
);
}
};
const returnSkeletonStack = () => {
if (!isDoneLoading) {
return (
);
}
};
return (
{returnContent()}
{returnSkeletonStack()}
);
};
```
## Width and Height
Use the `width` and `height` props to size the Skeleton. The default settings are `100%` for both width and height, so if no values are provided, the Skeleton will fill the parent container.
```jsx live
() => {
return (
);
};
```
## Variant
Use the `variant` prop to control the shape of the `Skeleton` component. The default is `rectangular`, which displays with no rounded edges. `rounded` is displayed with rounded edges and a border radius of `8px`. `circular` is displayed with fully rounded edges.
```jsx live
() => {
return (
);
};
```
## Animated
Animation is enabled by default. If you'd like to disable animation, pass in the `animated` prop and set it to a value of `false`.
```jsx live
() => {
return (
);
};
```
## Color
Use the `color` prop to set the color of the skeleton. Light mode default is white at 8% opacity. Dark mode default is white at 32% opacity.
```jsx live
() => {
return (
);
};
```
## Skeleton with Children
Add children to the `Skeleton` component by placing elements between the `Skeleton` tags. `Children` should be used to place nested skeletons within the main skeleton.
```jsx live
() => {
const Row = styled('View', {
display: 'flex',
flexDirection: 'row',
marginVertical: 15,
});
const InnerWrapper = styled('View', {
padding: '$md',
justifyContent: 'space-between',
height: '100%',
});
return (
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: style-sheet
category: Styling
title: StyleSheet
description: A utility to define and organize styles in an application
---
```jsx
import { StyleSheet } from '@uhg-abyss/mobile';
```
The `StyleSheet` module is a utility for defining and organizing styles in an application. It provides a way
to create an abstraction over native styles, ensuring performance optimization and consistency across different platforms.
## Key Features
- **Platform Consistency:** By using `StyleSheet`, you can define styles that work across both iOS and Android, ensuring a
uniform look and feel for your application.
- **Performance Optimization:** `StyleSheet optimizes style calculations which can significantly improve the rendering
performance of your app. It ensures that styles are calculated once then applied efficiently.
- **Readability and Maintainability:** Using `StyleSheet.create`, you can separate style definitions from your component logic,
making your code more readable and easier to maintain.
## Abyss StyleSheet vs. React Native StyleSheet
The Abyss StyleSheet extends the React Native StyleSheet API, so it can be used as a direct replacement and adds additional features. The additional
functionality works in conjunction with the [useStyleSheet](/mobile/hooks/use-style-sheet) hook.
### Token Typescript Support
`StyleSheet` extends the normal TypeScript declarations by allowing additional values to be placed in as values, such as
tokens, pixels and rem values.

### Media Query
Media queries allows to have different styles for different screens, platform, direction and orientation.
They are supported as properties with `@media` prefix.
- **width**: _``_
- **height**: _``_
- **min-width**: _``_
- **min-height**: _``_
- **max-width**: _``_
- **max-height**: _``_
- **direction**: (_`ltr`_ | _`rtl`_)
- **platform**: (_`ios`_ | _`web`_ | _`android`_)
- **orientation**: (_`landscape`_ | _`portrait`_)
- **aspect-ratio**: _``_
Resize browser window to see changes on the box.
```jsx live-expanded
const themedStyles = StyleSheet.create({
label: {
fontWeight: '$bold',
textAlign: 'center',
'@media (min-width: 800) and (max-width: 1100)': {
color: '$interactive1',
},
'@media (orientation: portrait)': {
paddingHorizontal: 16,
},
'@media (orientation: landscape)': {
paddingHorizontal: 44,
},
'@media (min-width: 900px)': {
color: '$white',
},
},
box: {
width: 250,
height: 200,
justifyContent: 'center',
backgroundColor: '$gray1',
'@media web': {
borderRadius: 8,
},
'@media (max-width: 700px)': {
width: 150,
backgroundColor: '$error2',
},
'@media (min-width: 900px)': {
width: 350,
backgroundColor: '$success1',
},
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
Resize browser window to see changes on the box.
);
});
```
### Pixel and Rem Support
Similar to [CSS3 rem unit](https://www.sitepoint.com/understanding-and-using-rem-units-in-css/) it allows to define any integer value as relative to the root element. In our case the root value
is is set to `16`. It makes easy to scale app depending on screen size and other conditions.
`StyleSheet` also accepts string pixel values (e.g. '16px'), which typically isn't available in React Native.
```jsx live
const themedStyles = StyleSheet.create({
text: {
color: '$info1',
fontSize: '2rem',
lineHeight: '50px',
fontWeight: '$semibold',
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return Abyss Mobile;
});
```
### Operations
Any value can contain one of following math operations: `*` , `/`, `+`, `-`. Operands can be numbers, tokens, pixels or rems.
There must be a space between operands and operations.
```jsx live
const themedStyles = StyleSheet.create({
box: {
backgroundColor: '$interactive3',
borderRadius: '$xl * 2',
padding: '$lg * 2',
borderWidth: '2 * 3',
borderColor: '$gray3',
},
text: {
fontSize: '$md * 3',
fontWeight: '$bold',
color: '$gray3',
textAlign: 'center',
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
Abyss Mobile
);
});
```
## Methods
### create()
```tsx
static create(styles: Object): Object;
```
Creates a StyleSheet style reference from the given object.
```jsx live
const themedStyles = StyleSheet.create({
container: {
flex: 1,
padding: '$lg',
backgroundColor: '$gray1',
},
title: {
marginTop: '$md',
paddingVertical: '$sm',
borderWidth: 4,
borderColor: '$gray3',
borderRadius: '$xl',
backgroundColor: '$interactive3',
color: '$gray3',
textAlign: 'center',
fontSize: '$xl',
fontWeight: '$xbold',
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
Abyss Mobile
);
});
```
### createThemed()
```tsx
static createThemed(theme: Theme, styles: Object): Object;
```
If you have direct access to a theme and do not want to use the `useStyleSheet` hook,
you can add the theme directly as a parameter to the `createThemed` function and use token
values in the StyleSheet. If your theme has token overrides, those can be used as well.
```jsx live
const theme = createTheme('uhc', {
theme: {
sizes: { notTooBigNotTooSmall: 200 },
radii: { fullyRounded: 1000000 },
},
});
const styles = StyleSheet.createThemed(theme, {
circle: {
backgroundColor: '$interactive3',
height: '$notTooBigNotTooSmall',
width: '$notTooBigNotTooSmall',
borderRadius: '$fullyRounded',
},
});
render(() => {
return ;
});
```
### compose()
```tsx
static compose(style1: Object, style2: Object): Object | Object[];
```
Combines two styles such that `style2` will override any styles in `style1`.
If either style is falsy, the other one is returned without allocating an array,
saving allocations and maintaining reference equality for PureComponent checks.
```jsx live
const page = StyleSheet.create({
container: {
flex: 1,
padding: 24,
backgroundColor: 'white',
},
text: {
fontSize: 30,
color: '#4B4D4F',
},
});
const lists = StyleSheet.create({
listContainer: {
flex: 1,
backgroundColor: '#D9E9FA',
},
listItem: {
fontStyle: 'italic',
fontWeight: 'bold',
},
});
const container = StyleSheet.compose(page.container, lists.listContainer);
const text = StyleSheet.compose(page.text, lists.listItem);
render(() => {
return (
Abyss Mobile
);
});
```
### flatten()
```tsx
static flatten(style: Object[]): Object;
```
Flattens an array of style objects, into one aggregated style object.
```jsx live
const page = StyleSheet.create({
container: {
flex: 1,
padding: 24,
alignItems: 'center',
},
text: {
color: '#000',
fontSize: 14,
fontWeight: 'bold',
},
code: {
marginTop: 12,
padding: 12,
borderRadius: 8,
color: '#666',
backgroundColor: '#EAEAEA',
},
});
const typography = StyleSheet.create({
header: {
color: '#004BA0',
fontSize: 30,
marginBottom: 36,
},
});
const flattenedTextStyle = StyleSheet.flatten([page.text, typography.header]);
render(() => {
return (
React NativeFlattened Text Style
{JSON.stringify(flattenedTextStyle, null, 2)}
);
});
```
### setStyleAttributePreprocessor()
```jsx render
Breaking changes will probably happen a lot and will not be reliably
announced. The whole thing might be deleted, who knows? Use at your own risk.
```
```tsx
static setStyleAttributePreprocessor(
property: string,
process: (propValue: any) => any,
);
```
Sets a function to use to pre-process a style property value.
This is used internally to process color and transform values.
You should not use this unless you really know what you are doing and have exhausted other options.
## Properties
### absoluteFill
A very common pattern is to create overlays with position absolute and zero positioning
(`position: 'absolute', left: 0, right: 0, top: 0, bottom: 0`), so `absoluteFill` can be
used for convenience and to reduce duplication of these repeated styles. If you want, absoluteFill
can be used to create a customized entry in a StyleSheet.
```jsx live
const themedStyles = StyleSheet.create({
container: {
height: 250,
},
box1: {
position: 'absolute',
top: 40,
left: 40,
width: 100,
height: 100,
backgroundColor: '$error1',
},
box2: {
width: 100,
height: 100,
backgroundColor: '$info1',
},
box3: {
position: 'absolute',
top: 120,
left: 120,
width: 100,
height: 100,
backgroundColor: '$success1',
},
text: {
color: '$white',
fontSize: 80,
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
123
);
});
```
### absoluteFillObject
Sometimes you may want absoluteFill but with a couple tweaks - absoluteFillObject can be
used to create a customized entry in a StyleSheet.
```jsx live
const themedStyles = StyleSheet.create({
container: {
height: 250,
},
box1: {
position: 'absolute',
top: 40,
left: 40,
width: 100,
height: 100,
backgroundColor: '$error1',
},
box2: {
...StyleSheet.absoluteFillObject,
top: 120,
left: 50,
width: 100,
height: 100,
backgroundColor: '$info1',
},
box3: {
...StyleSheet.absoluteFillObject,
top: 120,
left: 120,
width: 100,
height: 100,
backgroundColor: '$success1',
},
text: {
color: '$white',
fontSize: 80,
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
123
);
});
```
### hairlineWidth
This is defined as the width of a thin line on the platform. It can be used as the thickness
of a border or division between two elements
```jsx live
const themedStyles = StyleSheet.create({
container: {
flex: 1,
padding: '$xl',
},
row: {
padding: '$sm',
borderBottomColor: '$error1',
borderBottomWidth: StyleSheet.hairlineWidth,
},
});
render(() => {
const styles = useStyleSheet(themedStyles);
return (
AbyssMobile
);
});
```
## Usage with Abyss component
All Abyss components are able to parse objects from the StyleSheet directly, so there is no need to
use the `useStylesheet` hook if the styles are only going into Abyss components.
```jsx live
const styles = StyleSheet.create({
button: {
backgroundColor: '$info1',
borderWidth: '4px',
borderColor: '$error1',
},
});
render(() => {
return ;
});
```
---
id: tabs
category: Content
title: Tabs
description: The Tabs component is used to navigate to other pages, or sections of a page.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=9678-35146&mode=design&t=DgoELndJt2PBF6Lf-0
---
```jsx
import { Tabs } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Tabs',
inputs: [
{
prop: 'disableSwipe',
type: 'boolean'
},
{
prop: 'disableTransition',
type: 'boolean',
},
{
prop: 'color',
type: 'string'
},
],
}
Tab 1 ContentTab 2 ContentTab 3 Content
```
## Title
The `title` property provides a label that describes the purpose of the set of tabs. This is a required property as it gives screen reader users important context.
```jsx
Tab 1 ContentTab 2 ContentTab 3 Content
```
## Initial Tab (Uncontrolled)
If you do not need to subscribe to the tabs active state use the `initialTab` property to set the tab that is active at build time.
The default is set to the first tab in the sequence. If used instead of active the active state will be uncontrolled and handled internally by the component.
```jsx live
Tab 1 ContentContent starts with tab 2Tab 3 Content
```
## Active Tab (Controlled)
To control the Tabs active state, pass in the desired tab to the `activeTab` prop.
This must be used in combination with `onChange` to ensure that the active tab state is always current.
If no default state is passed the active tab will default to the first tab in the sequence.
```jsx live
() => {
const [activeTab, setActiveTab] = useState(2);
return (
Tab 1 ContentContent starts with tab 2Tab 3 Content
);
};
```
## Disable Swipe
Use the `disableSwipe` prop to disable swiping from one tab to another.
```jsx live
Swiping is now disabled. You can go to another tab by pressing one of the
tab buttons.
Tab 2 ContentTab 3 Content
```
## Disable Transition
Use the `disableTransition` prop to disable animating from one tab to another on either a swipe or a tab button press.
```jsx live
Tab 1 ContentTab 2 ContentTab 3 Content
```
## Scrollable Tabs and Menu
If there are more than three tabs, the Tabs component will scroll horizontally. If there are fewer than four tabs and the tabs fit on the screen horizontally, the scroll does not apply. If the tabs do not fit, a horizontal scroll is activated. Ideally, there should be no more than eight tabs.
The Tab menu opens up a bottom sheet with a list of the tabs. When there are fewer than four tabs, there is not a Tab menu.
```jsx live
Tab 1 ContentTab 2 ContentTab 3 ContentTab 4 ContentTab 5 ContentTab 6 Content
```
## Tab Bar Color
Use the `tabBarColor` prop to change the color of the tab bar.
```jsx live
Tab 1 ContentContent starts with tab 2Tab 3 Content
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
## Dynamic Type
Text and Icons on Tabs scale to 3XL.
```jsx render
```
---
id: test-provider
category: Providers
title: TestProvider
description: Used to determine strategy for testing
sourceIsTS: true
---
```jsx
import { TestProvider } from '@uhg-abyss/mobile';
```
The `TestProvider` is a component that provides a context for testing purposes. It allows you to specify a strategy for testing, which can be either "root" or "class".
The provider wraps the rest of the component tree and applies the specified strategy.
### Class strategy (default)
The `"class"` strategy (similar to default) allows testing of nested components by appending the Abyss class name to your `testID`. This creates unique identifiers for each element within the component.
For example, let's say the `testID` of [ProgressBar](/mobile/ui/ProgressBar) is set to `"your-test-ID"`.
```jsx
```
We can then refer to the classes for the ProgressBar.
```jsx render
```
The resulting test IDs will be _**`"your-test-ID-abyss-progress-bar-root"`**_ & _**`"your-test-ID-abyss-progress-bar-slide"`**_.
### Root strategy
The `"root"` strategy applies the `testID` only to the root element of the component. This means you won't be able to target nested elements within the Abyss component for testing.
For example, let's say the `testID` of [ProgressBar](/mobile/ui/ProgressBar) is set to `"your-test-ID"`.
```jsx
```
The resulting testID will still be **_`"your-test-ID"`_**.
```jsx render
```
---
id: text
category: Typography
title: Text
description: Used to create segments of text such as phrases, sentences, and paragraphs.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9470%3A32790
pagination_prev: mobile/ui/heading
# pagination_next: null
---
```jsx
import { Text } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Text',
inputs: [
{
prop: 'children',
type: 'string',
},
{
prop: 'color',
type: 'string',
},
{
prop: 'fontWeight',
type: 'string',
},
{
prop: 'size',
type: 'string',
},
{
prop: 'transform',
type: 'select',
options: [
{ label: 'none', value: 'none' },
{ label: 'capitalize', value: 'capitalize' },
{ label: 'lowercase', value: 'lowercase' },
{ label: 'uppercase', value: 'uppercase' },
],
},
{
prop: 'textAlign',
type: 'select',
options: [
{ label: 'left', value: 'left' },
{ label: 'center', value: 'center' },
{ label: 'right', value: 'right' },
],
},
],
}
Enter message here
```
## Set Global Text Font
One of the limitations of our library is the inability to install fonts into applications. Because of this, we have reserved a special token, `$text`, to be added in the createTheme function, which will add the font to all Heading components globally.
In the example below, the font 'UHCSans' is set as the text font and will now be applied to all Text components.
```jsx
import { ThemeProvider, createTheme } from '@uhg-abyss/mobile';
const theme = createTheme('uhc', {
theme: {
fonts: {
text: 'UHCSans',
},
},
});
const App = () => {
return ...;
};
```
Any individual Text component can override the font with the `fontFamily` prop.
## Color
Use the `color` property to set the color of the text. The default is set to `black`.
```jsx live
Some filler text - BlackSome filler text - errorSome filler text - hexSome filler text - color
```
## Sizes
Use the `size` property to change the size of the text. The default is set to md which is 16px. The values for each size are represented by `FontSize - LineHeight`.
```jsx live
Body 1 - Large / 18px - 24pxBody 2 - Medium / 16px - 20pxBody 3 - Small / 14px - 16pxSmall 1 - Extra Small / 12px - 16px
```
## Transform
Use the `transform` property to change the formatting of the text. Variants available include the default case, `capitalize` the first letter of each word, `lowercase` all letters, or `uppercase` all letters.
```jsx live
Default textCapitalize textLowercase textUppercase text
```
## Text Align
Use the `textAlign` prop to change the alignment of the text. Options include `left`, `center` and `right`. Default is `left`.
```jsx live
Left Aligned TextCenter Aligned TextRight Aligned Text
```
## Animated
Use the `animated` prop to use animation styles on the component.
The default is set to `false`.
```jsx live
() => {
const val = useRef(new Animated.Value(0)).current;
const animateTo = (toValue) => {
return Animated.timing(val, {
toValue,
duration: 2000,
easing: Easing.linear,
useNativeDriver: false,
});
};
useEffect(() => {
Animated.loop(Animated.sequence([animateTo(1), animateTo(0)])).start();
});
return (
Animated Text Color
);
};
```
### Nesting
Nested text components will inherit properties from the outer `Text`.
```jsx live
Outside Text...
Inside Text
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: text-field
category: Forms
title: TextField
description: Large input allows users to enter a large amount of text and data.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/branch/1Uml7LO8NTEWoBUAl4DTaG/Abyss-Mobile?type=design&node-id=18955-106021&t=DfyeirEdeaLCVZP9-0
---
```jsx
import { TextField } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'TextField',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'errorMessage',
type: 'string',
},
{
prop: 'isRequired',
type: 'boolean',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
]
}
() => {
const form = useForm();
return (
);
};
```
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [value, setValue] = useState('');
const onSubmit = () => {
console.log('Submitted:', value);
};
return (
);
};
```
## Label
Use the `label` prop to display a label above the text field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Error Message
Use the `errorMessage` prop to display a custom error message below the text field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Success Message
Use the `successMessage` prop to display a custom success message below the text field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the text field so users cannot enter a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## MaxLength
Use the `maxLength` prop to set the maximum length of characters accepted as input.
The amount of characters remaining will appear in the bottom right.
The default value of `maxLength` is 500.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
/>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: text-input
category: Forms
title: TextInput
description: Allows users to enter text into a UI.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=40307-5604&mode=design&t=dirQ2Ey2NpKNpNfn-0
---
```jsx
import { TextInput } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'TextInput',
inputs: [
{
prop: 'label',
type: 'string',
},
{
prop: 'hintText',
type: 'string',
},
{
prop: 'errorMessage',
type: 'string',
},
{
prop: 'type',
type: 'select',
options: [
{ label: 'Text', value: 'text' },
{ label: 'Password', value: 'password' },
{ label: 'Price', value: 'price' },
]
},
{
prop: 'isRequired',
type: 'boolean',
},
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'helpContent',
type: 'string',
},
]
}
() => {
const form = useForm();
return (
);
};
```
Note: If the TextInput is inside a ScrollView, verify the `keyboardShouldPersistTaps` prop on the ScrollView is set to `"always"` or `"handled"`
to allow pressing icons within the TextInput when the keyboard is open.
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm();
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [value, setValue] = useState('');
const onSubmit = () => {
console.log('Submitted:', value);
};
return (
);
};
```
## Placeholder
Use the `placeholder` prop to give users a short description in the input field before they enter a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Label
Use the `label` prop to display a label above the input.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Error Message
Use the `errorMessage` prop to display a custom error message below the input field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Success Message
Use the `successMessage` prop to display a custom success message below the input field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Disabled
Set the `isDisabled` prop to `true` to disable the input field so users cannot enter a value.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Types
Use the `type` prop to set the type of input field to be displayed. Types include: `'text'`, `'email'`, `'password'`, `'price'`, `'number'` and `'phone'`.
The default is `text`.
### Text
```jsx live
() => {
const form = useForm();
return (
);
};
```
### Password
```jsx live
() => {
const form = useForm();
return (
);
};
```
### Price
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Prefix
Use the `prefix` prop to display content before the input field. This is meant for text and decorative icons. The default prefix for `type='price'` is '$'.
```jsx live
() => {
const form = useForm();
return (
}
/>
);
};
```
## Suffix
Use the `suffix` prop to display content after the input field.
```jsx live
() => {
const form = useForm();
return (
);
};
```
## Action Icon
Use the `actionIcon` prop to pass in an actionable button. This can be used to further customize the input component.
```jsx live
() => {
const form = useForm();
const [isVisible, setIsVisible] = useState(false);
return (
}
onActionIconPress={() => setIsVisible(true)}
/>
setIsVisible(false)}
actionRight={
}
onActionRightPress={() => setIsVisible(false)}
>
This is where location search would be added
);
};
```
## Validation
Use the `validations` prop to set rules for the field to be valid. Each validation must have a key for it's name and an object that describes the validation. The object must have a message to display what should be validated. To create a custom validation, you can add a `validate` function that takes in the text as an argument and should return a boolean.
There are 5 built in validations: `minLength`, `maxLength`, `hasUppercaseLetters`, `hasLowercaseLetters` and `hasNumbers`. For the `minLength` and `maxLength` validations, you can pass in a `value` to determine the amount of characters to check for.
- minLength - Returns true if the amount of characters is less than the value.
Default: 8
- maxLength - Returns true if the amount of characters is less than the value.
Default: 20
- hasUppercaseLetters - Returns true if the text contains uppercase letters.
- hasLowercaseLetters - Returns true if the text contains lowercase letters.
- hasNumbers - Returns true if the text contains numbers.
To check the status of the validations, use the second parameter of the `onChangeText` prop.
```jsx live
() => {
const [text, setText] = useState('');
const success = useRef(false);
const handleChangeText = (text, validations) => {
console.log(validations);
success.current = Object.values(validations).every((v) => v === true);
setText(text);
};
return (
{
return text.endsWith('Q');
},
},
}}
/>
);
};
```
## Help Content
Use the `helpContent` prop to display a help icon in the top right of the container, which will display the provided content in a modal screen when pressed.
```jsx live
() => {
const form = useForm();
return (
This is some text used to explain something to the user, but is too
long to be hint text.
}
/>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
## Focus Guidance
Abyss does not control the focus of components on the screen when handling validation errors. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For text inputs, the focus should move back to the input when there is an error (e.g user typed too many characters).
```jsx render
```
---
id: theme-provider
category: Providers
title: ThemeProvider
description: An Abyss component that passes the theme object down the component tree.
---
```jsx
import { ThemeProvider } from '@uhg-abyss/mobile';
```
# Theming
Abyss theming supports changing colors, spacing, box-shadows, font families, font sizes and many other properties. Themes let you apply a consistent tone to your app. It allows you to customize all design aspects of your project in order to meet the specific needs of your business or brand. To configure the theme, wrap your app with a `ThemeProvider` component.
## Theme Provider
While Abyss components come with a default theme, the `ThemeProvider` is an optional component to change the theme globally.
`ThemeProvider` relies on the context feature of React to pass the theme down to the components, so you need to make sure that `ThemeProvider` is a parent of the components you are trying to customize.
This component takes a theme prop and applies it to the entire React tree that it is wrapping around. It should preferably be used at the root of The component tree.
```jsx render
```
```jsx
import { ThemeProvider, createTheme } from '@uhg-abyss/mobile';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
const themeOverride = {
theme: {
colors: {
primary1: '#002677',
primary2: '#FFFFFF',
secondary1: '#00BED5',
secondary2: '#F5B700',
},
fonts: {...},
},
};
const theme = createTheme('uhc', themeOverride);
const App = () => {
return ...;
};
AppRegistry.registerComponent(appName, () => App);
```
---
id: timeline-v2
category: Data
title: V2Timeline
description: A timeline step displays a single event or action of the timeline tracker.
design: https://www.figma.com/design/34gRQMq2NxFgeRynjqd24C/Documentation-%7C-UHC-Abyss-Mobile-App?node-id=931-225262&t=iguCSwnU4rMOZ7Dn-0
subDirectory: Timeline/v2
sourceIsTS: true
---
```jsx
import { V2Timeline } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'V2Timeline',
inputs: [
{
prop: 'type',
type: 'select',
options: [
{ label: 'Combo', value: 'combo' },
{ label: 'Card', value: 'card' },
{ label: 'Progress', value: 'progress' },
],
defaultValue: 'combo',
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'Default', value: 'default' },
{ label: 'Warning', value: 'warning' },
{ label: 'Error', value: 'error' },
{ label: 'Info', value: 'info' },
],
defaultValue: 'default',
},
{
prop: 'headingWeight',
type: 'string',
defaultValue: '$normal',
},
{
prop: 'currentStep',
type: 'select',
options: [
{ label: '0', value: 0},
{ label: '1', value: 1 },
{ label: '2', value: 2 },
{ label: '3', value: 3},
{ label: '4', value: 4},
{ label: '5', value: 5},
],
},
]
}
Button
}
/>
```
## Timeline Props & Usage
The `currentStep` prop is used to define the active timeline step. `currentStep` is required. To get the fully complete state for the timeline,
`currentStep` should be set to be greater than the total number of steps.
For example, if there are 3 steps, `currentStep` should be set to 4 to show the timeline as fully complete.
`variant` is used to select the step variant, The options are `default`, `warning`, `error`, and `info`.
Use the `type` prop to select what timeline type is most appropriate for you. The default `type` is `combo`.
- `combo` displays the active step card with the steps contained in a card directly below.
- `card` wraps the steps within a card. `card` does **NOT** contain the active step card.
- `progress` displays only the timeline steps without any wrapper.
`headingWeight` is used to modify the heading's fontWeight of every **non-active** step.
Use `content` to add custom components inside of the active step card.
Use `button` to add a button to the active step card.
## Timeline.Step Props & Usage
`Timeline.Step` is used to display an individual step, each step has access to the props below providing the ability to manipulate the data displayed. `Timeline.Step` must be a direct child of `Timeline`.
`isDisabled` will disable the step. When a step is disabled, it can still be accessed by `Timeline` via `currentStep`. A disabled step will not animate when active/complete.
`heading` defines the step's Heading.
`date` defines the date value displayed below `heading`, if a Date object is passed into `date` it will be formatted `MM/DD/YYYY`.
Use `paragraph` to add a paragraph below `date`.
`content` is used to add custom components to the bottom of the step.
```jsx live
() => {
const [activeStep, setActiveStep] = useState(1);
const [value, setValue] = useState(false);
return (
}
footer={
{}}
type="toggle"
value={value}
onChange={setValue}
/>
}
>
Button
}
/>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: timeline
category: Data
title: Timeline
description: A timeline step displays a single event or action of the timeline tracker.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=25304-37067&mode=design&t=lc6nuZ3zKpfWkpNH-0
---
```jsx
import { Timeline } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Timeline',
inputs: [
{
prop: 'type',
type: 'select',
options: [
{ label: 'Combo', value: 'combo' },
{ label: 'Card', value: 'card' },
{ label: 'Progress', value: 'progress' },
],
},
{
prop: 'variant',
type: 'select',
options: [
{ label: 'Default', value: 'default' },
{ label: 'Warning', value: 'warning' },
{ label: 'Error', value: 'error' },
{ label: 'Info', value: 'info' },
],
},
{
prop: 'titleWeight',
type: 'string',
},
{
prop: 'currentStep',
type: 'number',
},
]
}
```
## Timeline Props & Usage
The `currentStep` prop is used to define the active timeline step. `currentStep` is required. To get the fully complete state for the timeline,
`currentStep` should be set to be greater than the total number of steps. For example, if there are 3 steps, `currentStep` should be set to 4 to show the timeline as fully complete.
`variant` is used to select the step variant, The options are `default`, `warning`, `error`, and `info`.
Use the `type` prop to select what timeline type is most appropriate for you. The default `type` is `combo`.
- `combo` displays the `active step card` with the steps contained in a card directly below.
- `card` wraps the steps within a card. `card` does **NOT** contain the `active step card`.
- `progress` displays only the timeline steps without any wrapper.
`titleWeight` is used to modify the title's fontWeight of every **non-active** step.
Use `content` to add custom components inside of the `active step card`.
Use `button` to add a button to the `active step card`.
```jsx live
() => {
const [variant, setVariant] = useState('default');
const [currentStep, setCurrentStep] = useState(2);
const Heading = styled('Text', {
paddingVertical: 12,
fontSize: 24,
color: '$gray4',
fontWeight: '$medium',
});
const changeValue = (operator) => {
setCurrentStep((v) => Math.min(Math.max(v + operator, 1), 3));
};
return (
Type: Combo
}
button={
}
>
Type: CardType: Progress
);
};
```
## Timeline.Step Props & Usage
`Timeline.Step` is used to display an individual step, each step has access to the props below providing the ability to manipulate the data displayed. `Timeline.Step` must be a direct child of `Timeline`.
`isDisabled` will disable the step. When a step is disabled, it can still be accessed by `Timeline` via `currentStep`. A disabled step will not animate when active/complete.
`title` defines the step's title.
`date` defines the date value displayed below `title`, if a Date object is passed into `date` it will be formatted `MM/DD/YYYY`.
Use `description` to add a description below `date`.
`content` is used to add custom components to the bottom of the step.
```jsx live
() => {
const [activeTab, setActiveTab] = useState(1);
return (
}
>
Button
}
/>
);
};
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
---
id: toast
category: Feedback
title: Toast
description: Feedback on the result of an operation that disappears without user action.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=9982%3A35190&t=g1imyz1B5bFHjcvc-0
---
```jsx
import { Toast } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'Toast',
inputs: [
{
prop: 'variant',
type: 'select',
options: [
{ label: 'success', value: 'success'},
{ label: 'warning', value: 'warning'},
{ label: 'error', value: 'error'},
{ label: "info", value: 'info'},
]
},
{
prop: 'children',
type: 'string',
},
{
prop: 'href',
type: 'string',
},
{
prop: 'linkText',
type: 'string',
},
{
prop: 'heading',
type: 'string',
},
{
prop: 'underlineLink',
type: 'boolean',
},
{
prop: 'isClosable',
type: 'boolean',
},
],
}
Link to Google
```
## Variant
Use the `variant` property to set the color of the `Toast`.
The options are `success`, `warning`, `error`, and `info`. The default is `success`.
```jsx live
You can only compare up to 4 providersYour estimate has been saved!Be careful what you wish for!Your estimate did not save!
```
## Icons
Use the `icon` prop to pass in a specific Icon component. The expected size for the icon is 18px to stay consistent with the height of the text within the Toast. Find further guidance on material icons in the [Material Icons Tab](/mobile/ui/icon-material/).
```jsx live
}>
filled white favorite
}
>
outlined warning
}
>
outlined local_activity
```
## Heading
Use the `heading` prop to add text above the description. This is optional and should only be used to summarize the paragraph if needed.
```jsx live
Description text goes here
```
## Text
Change the children of the Toast to set the text.
```jsx live
Your estimate has been saved!
```
## onPress
Use the `onPress` function to handle the action when the link within the Toast is pressed.
```jsx live
{
console.log('Link Pressed');
}}
href="https://www.github.com"
linkText="Make A Wish"
>
You can only compare up to 4 providers
```
## Link Text
Change the `linkText` prop to set the text.
Use the `underlineLink` prop to underline the linkText.
```jsx live
Your estimate has been saved!
console.log('Link pressed')}
>
Be careful what you wish for!
```
## Dismissible Toast
Use the `isClosable` prop to create a dismissible toast. Instead of a set duration, the toast will remain on the screen until a user presses the close button. Accessibility requires a toast that has a link to be dismissible, this cannot be changed.
```jsx live
Your estimate has been saved!
Your estimate did not save!
```
## Toast Functions
### Toast.show()
```ts
Toast.show(options: ShowToastOptions): string
```
The Toast will appear at the top of the screen for a default duration of 7 seconds per accessibility. It is recommended to increase the duration if more content is placed within the toast. A toast with a heading and description, or a link, should account for the time a user may need to interact with the toast. To use Toast.show(), import the ToastProvider.
```jsx
import { ToastProvider } from '@uhg-abyss/mobile';
```
- duration - Sets the time before the toast disappears.
- placement - Determines the placement of the toast.
- offset - Offset space for both the top and bottom of the toast.
- onPress - Callback fired when the link is pressed.
- onClose - Callback fired when the toast disappears.
- href - Sets the URL of the link.
- icon - Adds an icon to the Toast component.
- linkText - Sets the text of the link.
- heading - Sets the heading of the toast.
- text - Sets the text of the Toast Message.
- variant - Sets the color of the toast.
- animationDuration - Sets the transition time of the toast.
- underlineLink - Sets the heading of the toast.
- isClosable - Adds close icon to close the toast. The toast will not disappear
until the close icon is pressed.
In addition, Toast.show() also accepts the same props as the Toast component.
### Toast.update()
```ts
Toast.update(id: string, options: ShowToastOptions): void
```
The function updates the already shown toast by passing in the unique id of the respective toast and the parameters to update.
### Toast.hide()
```ts
Toast.hide(id: string): void
```
The function hides the toast by specifying a unique id that is returned by Toast.show().
### Toast.hideAll()
```ts
Toast.hideAll(): void
```
The function hides all toasts rendered on the screen.
```jsx live
const StyledButton = styled(Button, {
marginBottom: 10,
});
const delay = (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
};
const Screen = () => {
const showToast = () => {
Toast.show({
text: 'Your estimate has been saved!',
onClose: () => console.log('Closed'),
placement: 'top',
variant: 'success',
});
};
const showClosableToast = () => {
Toast.show({
text: 'Your estimate did not save!',
onClose: () => console.log('Closed'),
variant: 'error',
isClosable: true,
});
};
const showUpdatableToast = () => {
const toastId = Toast.show({
text: 'You can only compare up to 4 providers',
heading: 'Changes not saved',
variant: 'error',
placement: 'top',
onClose: () => {
return console.log('Closed');
},
isClosable: false,
});
delay(3000).then(() => {
Toast.update(toastId, {
text: 'You picked one of our providers. Great choice!',
variant: 'success',
isClosable: true,
heading: 'Changes Saved',
});
});
};
const showHidableToast = () => {
const toastId = Toast.show({
text: 'You can only compare up to 5 providers',
heading: 'Changes not saved',
variant: 'warning',
placement: 'top',
onClose: () => {
return console.log('Closed');
},
isClosable: true,
});
delay(3000).then(() => {
Toast.hide(toastId);
});
};
return (
Show Toast
Show Closable Toast
Show & Updatable Toast
Show & Hide ToastHide all Toasts
);
};
render(() => {
return (
);
});
```
```jsx render
```
```jsx render
```
```jsx render
```
```jsx render
```
## Focus Guidance for Dismissable Toasts
Abyss does not control the focus of components on the screen when a dissmissable Toast is closed. To meet
accessibility guidelines, the focus must be set to the previous node when closed. The [useSetFocus](/mobile/hooks/use-set-focus) hook can be used for this.
For example, if a button is pressed that triggers a Toast, focus must return to that button once it is closed, so that a screen reader or keyboard user may continue using the app where they left off.
```jsx render
```
---
id: toggle-switch
category: Forms
title: ToggleSwitch
description: Used to switch between 2 modes.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?type=design&node-id=9549-32657&mode=design&t=7hfDPwhG2zrhoDjN-0
---
```jsx
import { ToggleSwitch } from '@uhg-abyss/mobile';
```
```jsx sandbox
{
component: 'ToggleSwitch',
inputs: [
{
prop: 'isDisabled',
type: 'boolean',
},
{
prop: 'showAccessibilityIcon',
type: 'boolean',
},
]
}
() => {
const form = useForm();
return (
);
};
```
## Usage
The toggle switch adapts its style based on the operating system. Use the system dropdown at the top right of the screen to update.
## useForm (recommended)
Using the `useForm` hook with `FormProvider` sets state for the component.
```jsx live
() => {
const form = useForm({
defaultValues: {
'toggle-switch-form': true,
},
});
const handleSubmit = (data) => {
console.log('Submitted:', data);
};
return (
);
};
```
## useState
Using the `useState` hook gets values from the component state.
```jsx live
() => {
const [example1, toggleExample1] = useState(true);
return ;
};
```
## isDisabled
The `isDisabled` prop when set to true will cause the ToggleSwitch to be rendered in a disabled state, preventing user interaction and providing visual feedback that the component cannot be toggled.
```jsx live
() => {
const form = useForm({
defaultValues: {
'toggle-switch-disabled-one': true,
'toggle-switch-disabled-two': false,
},
});
return (
);
};
```
## showAccessibilityIcon
The `showAccessibilityIcon` prop when set to true will cause the ToggleSwitch to be rendered with the accessibility icon.
```jsx live
() => {
const form = useForm({
defaultValues: {
'toggle-switch-accessibility-one': true,
'toggle-switch-accessibility-two': true,
'toggle-switch-accessibility-three': false,
},
});
return (
);
};
```
```jsx render
```
```jsx render
```
## Dynamic Type
ToggleSwitch scales up to 3XL.
```jsx render
```
---
id: translate
category: I18n
title: Translate
description: Used to get the translated string from the i18n object.
---
## Usage
```jsx
import { Translate } from '@uhg-abyss/mobile/ui/Translate';
```
## Usage
The `Translate` component can use a function as a child which passes an object with the `t` and `i18n` properties. The `t` property is a function that is used to get the translated string from the i18n object.
The `i18n` property is the i18n object.
The `t` function takes two arguments.
```jsx
t(key: string, replacements?: object): string
```
The `key` argument corresponds to the key in the i18n object. The `replacements` argument is an object that contains the values to replace in the translated string.
## Example
Let's use an example to illustrate how to use the `Translate` component. In the [TextField](/mobile/ui/text-field) component, we have a text block that displays the remaining characters available
to be typed in the text field. We can get that value with the key `TextField.charactersRemaining`.
```jsx live-expanded
{({ t }) => {t('TextField.charactersRemaining')}}
```
If we want to replace the value of the remaining characters, we can pass in the `replacements` object with the key `count`.
Replacement values should always appear in double curly braces, (e.g. `{{count}}`).
```jsx live-expanded
{({ t }) => {t('TextField.charactersRemaining', { count: 10 })}}
```
We can also use the component to get the translated string from the i18n object.
```jsx live-expanded
{({ i18n }) => {i18n.TextField.charactersRemaining}}
```
```jsx render
React.ReactNode',
description: '',
},
]}
/>
```
---
id: video-player
category: Media
title: VideoPlayer
description: A component that provides playback of video.
design: https://www.figma.com/file/wCMblLsq9TxAQvKzY3EfCt/Abyss-Mobile?node-id=47768%3A3163&mode=dev
---
```jsx
import { VideoPlayer } from '@uhg-abyss/mobile/ui/VideoPlayer';
```
## Setup
VideoPlayer requires `react-native-video` to be install as a dependency. To start, install the [react-native-video](https://www.npmjs.com/package/react-native-video) package inside of your mobile folder, then follow the react-native-video [Installation directions](https://www.npmjs.com/package/react-native-video#installation).
## Basic usage
`VideoPlayer` can be used with a single `source` prop. In this configuration it will use the native controls in `iOS`, and abyss specific controls for `Android`.
`VideoPlayer` is built around [react-native-video](https://www.npmjs.com/package/react-native-video), and thus has the ability to consume any prop available in `react-native-video`, execpt: `fullscreen`.
```jsx
```
```jsx render
```
## Customization
You can use the `thumbnail` prop to display a custom thumbnail before the video is started.
```jsx
}
/>
```
## Subtitles/CC
Be sure to add closed captions to your video via the `textTrack` prop.
Closed Captions are required for accessibility. You can provide multiple text tracks, and select the default one using the `selectedTextTrack` prop.
```jsx
```
## Accessibility
- Closed Captions is required for all videos.
- Be sure to provide an `videoTitle` prop to the `VideoPlayer` component. This will be used as the A11y title for the video.
- It is recommneded to provide a text transcript on the same page as the video player.
```jsx render
```
```jsx render
```
```jsx render
```
---
id: overview
category: White Labeling
title: Overview
hideHeaderActions: true
---
## White Labeling with Abyss
Abyss is comprised of a group of designers, accessibility experts, engineers, and QE who work together to build design kits, component libraries, and documentation sites that are packed with prebuilt, reusable or global assets that align with our enterprise branding and accessibility standards to ensure quality, drive consistency, and help teams reduce redundancies in design and code, forging seamless collaboration across product portfolios.
Abyss helps teams create exceptional digital solutions and user journeys, enhancing user experience while driving familiarity for our end users across different platforms. Teams can feel confident using Abyss, leveraging our components and assets, knowing they don’t have to do design or accessibility checks to ensure compliance.
In addition to reusability, we also offer flexibility for customization, ensuring products remain streamlined and effortlessly maintainable through the combination of leveraging what’s available in Abyss and allowing teams to focus more of their time on specific user cases or product needs. This includes white labeling, which allows for design and engineering teams to take any of the reusable components, or building blocks, and apply their own styling and themes, rather than leveraging enterprise brand themes for UHC, UHG, or Optum.
### The Goal
The Abyss brand aims to empower white label consuming teams to apply their own themes to the design system, ensuring flexibility for both development and design teams to fully own and manage their tokens. This approach reduces dependency on the core design team for updates while preserving a unified system structure, allowing teams to maintain consistency and efficiency in their digital solutions.
## Glossary
**White Labeling** - The process of adapting a framework to support a specific brand or multiple brands not supported by Abyss, while allowing for customization.
**Tokens Studio for Figma** - Token Studio is the backbone of the abyss tokening strategy. It's a centralized place to create, manage, and export tokens to both Figma variables and as a dev-consumable JSON file. Read more on Tokens Studio here.
**Tokens** - Tokens are key-value pairs consisting of the Token Name and value. These represent fundamental design decisions as abstract, reusable data. They allow for easy adaptation and customization of the Abyss Design System while maintaining consistency for any brand or style.
Abyss currently supports tokens for: color, spacing, sizing, border radius, border width, and opacity.
- `[Token Key]: [Token Value]`
**Theme** - A set of tokens that define a brand.
**Base Theme** - A theme whose tokens are managed, published and versioned by Abyss, such as `Optum` and `UHC`.
**White-Labeled Theme** - A customized theme whose tokens are managed, published, and versioned by an Abyss consumer for the brands they maintain.
## Tokens
To effectively leverage white labeling with Abyss, it's important to understand how tokens function within the design system. Teams looking to white label can use the Abyss token formula and variable map, applying their own values to achieve the desired theming and styling. This standardized token formula ensures consistent application of styles across experiences. Its reusability not only streamlines the process but also provides significant time savings and efficiencies for teams building and maintaining digital experiences.
### What are Tokens?
Tokens are even smaller building blocks (or sub-atoms) of the design system, used in place of hardcoded values and built in alignment with various standards that allow teams to maintain scalability and consistency. Each token category has its own structure based on defined rules and guidelines, representing design decisions that set the standard for the design system. When creating new or enhanced designs, use tokens to create a cohesive UI that follows established standards and patterns.
For a deeper dive into using tokens, visit our [Tokens](/mobile/brand/uhc/tokens) documentation.
---
id: design
category: White Labeling
title: Design Strategy
description: Leveraging design tokens (variables) and Figma libraries to rebrand the Abyss Design System
hideHeaderActions: true
---
## Overview
Utilizing our white labeling strategy, teams can work with Figma files to create new themes for their customers independently of the Abyss team. This allows you to preview themes in Figma using Abyss components, provide design decisions to developers, implement those design decisions into software, and migrate to new Abyss versions without losing your design decisions.
_ Note the Figma links below require having a Figma account and being granted access to the necessary project. If you don't have access, please click the "request access" button and reach out to Jess Wolff (jessica_wolff@uhc.com) for approval._
## Figma Files and Assets
### Global Files (Abyss owned)
The master library files contain tokenized components used across the design system. They are separated into two categories: design-ready and dev-ready. The design-ready components, if not in the backlog, will have the sprint they’re slotted for in the component description.
### Foundations and Token Files (Abyss owned)
Contains all the tokens in the form of Figma variables, as well as documentation components for color semantic tier taxonomy.
These files are fed by the Tokens Studio plugin and connected with the global versioned and design-ready files as a library.
### Figma File Duplicates (not owned by Abyss)
Abyss will provide duplicates of all six files - three per platform:
- a versioned file with dev-ready components
- a file with design-ready components
- a file with tokens (variables)
White label teams are responsible for setting up the files following provided documentation by Abyss. The Abyss version, at the time of duplicating the file, will be noted in the file name. White label teams are responsible for maintaining these files in a way that preserves component structure and functionality and token taxonomy.
## Design Guides
The Abyss Design Team has provided detailed documentation on how to utilize tokens to rebrand our design system.
- Check out the Getting Started documentation on Figma to learn more about applying your own theme to the Abyss Figma Library.
- Understanding token taxonomy is crucial for making informed decisions when modifying color tokens. The Token Taxonomy Guide describes ways to utilize the Abyss token taxonomy documentation and learning how color is applied throughout.
- The most efficient way to rebrand the Abyss library is by leveraging the provided Figma-branded library file and the Token Studio plugin. Learn how to edit core tokens here.
- For cases when the branding requires a color that is non-existent in the Abyss core tokens or belongs in a different bucket, Abyss Design has outlined a guide to remapping semantic tokens.
- It is important to stay aligned with the design system. Abyss has two ways of doing so:
- Allowing teams to recreate updates.
- Allowing teams to stick to a specific version of Abyss and migrate to a newer version at their own pace.
---
id: introduction
category: Developer Guide
title: Introduction
description: Implementing a White Label Theme
hideHeaderActions: true
---
## Prepare
### Token Syncing
- Familiarize yourself with Token Syncing in Tokens Studio. This is an optional step that would allow you to skip importing the token JSON file manually
### Manual import
- Get Token JSON from [Design](/mobile/white-labeling/design)
- Add to Repository
## 1. Combine Tokens
Use the `flattenTokens` function to flatten and combine the imported tokens from the JSON file into a single object consumable by [createTheme](/mobile/tools/create-theme). This function supports a layered system where tokens from different themes can override core, semantic, and component-level tokens. Check out the [flattenTokens](/mobile/tools/flatten-tokens) documentation for an in-depth look at the function.
_Note that this approach assumes the token files are exported from Figma Token Studio._
```typescript
import { flattenTokens } from '@uhg-abyss/mobile';
import core_01 from '../01_core.json';
import semantic_02 from '../02_semantic.json';
import brand_03 from '../03_brand.json';
const brandTheme = flattenTokens(core_01, semantic_02, brand_03);
```
For maintaining multiple brands, refer to the [multi-brand](/mobile/white-labeling/developer-guide/multi-brand-implementation) tutorial.
## 2. Create Theme Object
Use the [createTheme](/mobile/tools/create-theme) function to create a theme object from the flattened tokens. This theme object will be used to apply the white label theme to your application. The `createTheme` function takes two arguments: the name of the base theme (`"uhc"`, `"uhg"`, `"optum"`, or `"abyss"`) and an optional object for any overrides you wish to apply, such as your white-labeled theme.
```typescript
import { createTheme } from '@uhg-abyss/mobile';
const theme = createTheme('optum', brandTheme);
```
## 3. Implement New Theme
Wrap your application with the [ThemeProvider](/mobile/ui/theme-provider) and pass in the created theme object. This ensures that the theme is applied globally to all components within your application.
```typescript
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import { ThemeProvider, createTheme, flattenTokens } from '@uhg-abyss/mobile';
import core_01 from '../01_core.json';
import semantic_02 from '../semantic_02.json';
import brand_03 from '../03_brand.json';
const brandTheme = flattenTokens(core_01, semantic_02, brand_03);
const theme = createTheme('optum', brandTheme);
const App = () => (
{/* Your application components */}
);
AppRegistry.registerComponent(appName, () => App);
```
---
id: multi-brand-implementation
category: Developer Guide
title: Multi-Brand Themes
description: White Labeling for Multiple Brands
hideHeaderActions: true
---
## 1. Combine Brand Tokens
Use the `flattenTokens` function to combine the tokens from the JSON files into a single object for each different brand. This function supports a layered system where tokens from different themes can override core, semantic, and component level tokens. Check out the [flattenTokens](/mobile/tools/flatten-tokens) documentation for an in-depth look at the function.
```typescript
import { flattenTokens } from '@uhg-abyss/mobile';
import brand_A from '..tokens/brand_A.json';
import brand_B from '..tokens/brand_B.json';
const brandThemeObjectA = flattenTokens(core, brand_A);
const brandThemeObjectB = flattenTokens(core, brand_B);
```
## 2. Create Theme Objects
Use the [createTheme](/mobile/tools/create-theme) function to create a theme object from the flattened tokens. This theme object will be used to apply the white label theme to your application. The `createTheme` function takes two arguments: the name of the base theme (`"uhc"`, `"uhg"`, `"optum"`, or `"abyss"`) and an optional object for any overrides you wish to apply, such as your white-labeled theme.
```typescript
import { createTheme } from '@uhg-abyss/mobile';
const brandThemeA = createTheme('optum', brandThemeObjectA);
const brandThemeB = createTheme('optum', brandThemeObjectB);
```
## 3. Implement New Themes
Wrap your application with the [ThemeProvider](/mobile/ui/theme-provider). Depending on the brand selected, pass in the needed brand theme to the theme object. This ensures that the brand theme is applied globally to all components within your application.
```typescript
import { ThemeProvider, createTheme, flattenTokens } from '@uhg-abyss/mobile';
import core from '..tokens/core.json';
import brand_A from '..tokens/brand_A.json';
import brand_B from '..tokens/brand_B.json';
// flatten each brands tokens
const brandThemeObjectA = flattenTokens(core, brand_A);
const brandThemeObjectB = flattenTokens(core, brand_B);
// create each brand theme
const brandThemeA = createTheme('optum', brandThemeObjectA);
const brandThemeB = createTheme('optum', brandThemeObjectB);
const App = () => (
{/* Your application */}
);
```