-
Notifications
You must be signed in to change notification settings - Fork 2
App Style Guide
francelu edited this page Dec 6, 2024
·
33 revisions
The purpose of this page is to
- serve as a reference for the style that the app should follow
- be consistent with the app style
This page can be constantly updated, modified and re-discussed along the development of the app!
Variable Name | Default Value | Description/Usage |
---|---|---|
extraSmall |
0.dp | Not yet used. |
small1 |
0.dp | Base spacing value used for scaling other dimensions. |
small2 |
small1 * 2 |
Scaffold 's LazyColumn vertically spacedBy() . Add spacing to the top of a component on a screen (see ProfileSection ). In a button, space between the icon and the text. |
small3 |
small1 * 4 |
Scaffold 's LazyColumn vertical padding. Card 's horizontal padding (and spacing for alert item). |
medium1 |
small1 * 6 |
Auth screens' in-between padding. Auth's Box horizontal padding. |
medium2 |
small1 * 8 |
Not yet used. |
medium3 |
small1 * 10 |
Scaffold 's LazyColumn horizontal padding. |
large |
small1 * 15 |
Auth screen's LazyColumn 's horizontal padding. |
borderLine |
1.dp | Auth's Box 's border. HorizontalDivider thickness . If needed, a Button 's border. |
buttonHeight |
40.dp | Not yet used, but should be used (?). |
cardElevation |
4.dp |
Card 's elevation = CardDefaults.cardElevation(...) . |
cardRoundedSize |
small1 * 3 |
Card 's shape is RoundedCornerShape(size = ...) . |
iconSize |
0.dp | Normal Icon 's Modifier.size(...) . |
iconSizeSmall |
iconSize * 2 / 3 |
Smaller Icon s' size (e.g., alert's cards). |
iconButtonSize |
iconSize * 2 |
The size of the button around an icon (for IconButton ). |
profilePictureSize |
small1 * 50 |
GlideImage 's Modifier.size(...) . |
roundedPercent |
50 | Round perfectly the left and right edges RoundedCornerShape(%) of a component. |
The typographies font size are adapted to the screens' size. However, there are only a few ones that have been set from the Typography
:
Text Style | Usage | Example |
---|---|---|
headlineMedium |
Big Button s |
CreateAlertScreen 's Button
|
headlineSmall |
TabRow 's Tab text |
Tab s in AlertListsScreen
|
titleLarge |
Extra big textx | AuthenticationWelcomeText |
titleMedium |
TopAppBar title |
TopAppBar 's title Text
|
titleSmall |
"Sections" on screens | "Name" field on ProfileScreen , ProfileSection
|
bodyLarge |
Short and big instructions on screens | Authentication screens' instruction texts |
bodyMedium |
Smaller / long instructions on screens Normal buttons |
Profile's description and save button |
labelLarge |
placeholder in OutlinedTextField + DropDownMenu s |
OutlinedTextField s, DropdownMenu s Alert's name |
labelMedium |
label in OutlinedTextField + DropDownMenu s |
OutlinedTextField s, DropdownMenu s Alert's data & edit button text |
labelSmall |
BottomNavigationBar s texts |
NavigationBarItem 's label's text |
If further typographies will be needed, the above will be updated.
// Screen
Scaffold(
modifier = Modifier.fillMaxSize().testTag(CreateAlertScreen.SCREEN),
topBar = { TopAppBar(title = SCREEN_TITLE) },
bottomBar = {
BottomNavigationMenu(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute(),
)
},
) { paddingValues ->
Column(
modifier =
Modifier.fillMaxSize()
.padding(paddingValues)
.padding(
horizontal = MaterialTheme.dimens.medium3,
vertical = MaterialTheme.dimens.small3,
)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement =
Arrangement.spacedBy(MaterialTheme.dimens.small2, Alignment.CenterVertically),
) {
// Components on the screen should have no padding.
// However, e.g. profile section, if you need more padding, it should be as follow
Text(
text = ...,
modifier = Modifier.padding(vertical = MaterialTheme.dimens.small1),
)
}
}
// Example with message field
var isFocused by remember { mutableStateOf(false) }
OutlinedTextField(
modifier =
Modifier.fillMaxWidth()
.wrapContentHeight()
.testTag(CreateAlertScreen.MESSAGE_FIELD)
.onFocusEvent { focusState -> isFocused = focusState.isFocused },
value = message,
onValueChange = { message = it },
textStyle = MaterialTheme.typography.labelLarge,
label = {
Text(
text = MESSAGE_FIELD_LABEL,
style =
if (isFocused || message.isNotEmpty()) MaterialTheme.typography.labelMedium
else MaterialTheme.typography.labelLarge)
},
placeholder = {
Text(text = MESSAGE_FIELD_PLACEHOLDER, style = MaterialTheme.typography.labelLarge)
},
minLines = 3,
)
// General instruction texts, example from auth instruction text
Text(
modifier =
Modifier.fillMaxWidth().wrapContentHeight().testTag(SignInScreen.INSTRUCTION_TEXT),
text = SIGN_IN_INSTRUCTION,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyLarge,
)
// Longer instruction texts, example from create alert
Text(
text = INSTRUCTION_TEXT,
modifier = Modifier.testTag(CreateAlertScreen.INSTRUCTION_TEXT),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
)
// Buttons
Button(
modifier = Modifier.wrapContentSize().testTag(testTag),
onClick = ...,
enable = true,
) {
Text(text = text, style = MaterialTheme.typography.bodyMedium)
}
// Example from alert lists' [NoAlertDialog]
Card(
modifier = Modifier.wrapContentSize().testTag(AlertListsScreen.NO_ALERTS_CARD),
shape = RoundedCornerShape(size = MaterialTheme.dimens.cardRoundedSize),
elevation = CardDefaults.cardElevation(defaultElevation = MaterialTheme.dimens.cardElevation),
) {
Column(
modifier = Modifier.wrapContentSize().padding(MaterialTheme.dimens.small2),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement =
Arrangement.spacedBy(MaterialTheme.dimens.small2, Alignment.CenterVertically),
) {
...
}
}
Here's a link to Color system.
For best practices, see Color roles or see this comment in issue #179.
Primary | Secondary | Tertiary | Error |
---|---|---|---|
primary |
secondary |
tertiary |
error |
onPrimary |
onSecondary |
onTertiary |
onError |
primaryContainer |
secondaryContainer |
tertiaryContainer |
errorContainer |
onPrimaryContainer |
onSecondaryContainer |
onTertiaryContainer |
onErrorContainer |
Background ? | Surface | Outline | Scrim | Inverse |
---|---|---|---|---|
background |
surface |
outline |
scrim |
inverseSurface |
onBackground |
onSurface |
- | - | inverserOnSurface |
- | surfaceVariant |
outlineVariant |
- | inversePrimary |
- | onSurfaceVariant |
- | - | - |
- | sufaceDim |
- | - | - |
- | surfaceBright |
- | - | - |
surfaceContainer
-Lowest
, Low
, -
, High
, Highest
Note: This wiki page is mostly a paraphrasing and summary of the style guide found in https://m3.material.io/.
These are the very basic rules to follow when implementing the design.
- Investigate what is the standard way of implementing UI.
- For instance, for dialogs, use the
Dialog
composable: https://developer.android.com/develop/ui/compose/components/dialog
- Use high contrast.
- Contrast ratios: represent how different one color is from another color. The greater the difference in relative luminance between the colors, the greater the difference between the colors.
Text type | Color contrast ratio |
---|---|
Large text (at 14 pt bold/18 pt regular and up) and graphics | 3:1 against the background |
Small text | 4.5:1 against the background |
- Place important actions at the top or bottom of the screen (reachable with shortcuts)
- Place related items of a similar hierarchy next to each other
- Identify headings based on content hierarchy, rather than visual styling
- Headings should not skip a level, for example, don't go from H2 to H4 without using an H3
- Map content on your pages to headings (H1–H6) in sequential order based on the hierarchy of your content
- A single H1 for the page title is recommended
Heading | Font size (in dp) |
---|---|
H1 | 32 |
H2 | 24 |
H3 | 21 |
H4 | 16 |
H5 | 12 |
H6 | 11 |
- Touch targets are the parts of the screen that respond to user input, extending beyond the visual bounds of an element.
- Design tokens point to style values like colors, fonts, and measurements
- Use design tokens instead of hardcoded values
- Each token is named for how or where it’s used (for example, md.fab.container.color sets the container color for a FAB)
- Even if a token’s end value is changed, its name and use remain the same
- They ensure consistency between the mock-up and the implementation
- A token consists of:
- A code-like name, such as md.ref.palette.secondary90
- An associated value, such as #E8DEF8
- Types of tokens:
- Reference tokens: All available tokens with associated values
- System tokens: Decisions and roles that give the design system its character, from color and typography, to elevation and shape
- Component tokens: The design attributes assigned to elements in a component, such as the color of a button icon
From #16 comments