diff --git a/docs/theming/dark-mode.md b/docs/theming/dark-mode.md index 8d42d01a0ea..e4c36d9ecb8 100644 --- a/docs/theming/dark-mode.md +++ b/docs/theming/dark-mode.md @@ -4,8 +4,6 @@ initialTab: 'preview' inlineHtmlPreviews: true --- -import Codepen from '@components/global/Codepen'; - Dark Mode to Change Color Schemes and CSS Properties -Ionic makes it easy to change the themes of your app, including supporting dark color schemes. With growing support for dark mode in native apps, developers are now looking to add it to their apps to support user preferences. +Ionic makes it easy to change the themes of your app, including supporting dark color schemes. Dark mode is a display setting that changes all of an app's views to a dark theme. It has system-wide support on iOS and Android, making it highly desirable for developers to add to their apps. ## Using Media Queries -The first way to enable dark mode is by using the [CSS media query for the user's preferred color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). This media query will hook into the system setting of the user's device and apply the theme if a dark mode is enabled. +The modern way to enable dark mode is by using the [CSS media query for the user's preferred color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). This media query will hook into the system setting of the user's device and apply the theme if dark mode is enabled. Ionic Framework starters use this method to include the dark theme. ```css @media (prefers-color-scheme: dark) { :root { - /* dark mode variables go here */ + /* Dark mode variables go here */ } } ``` -Currently, the `prefers-color-scheme` media query has [limited browser support](https://caniuse.com/#feat=prefers-color-scheme), so users will not be able to benefit from having the dark mode applied using this media query in certain browsers. However, the dark mode can still be applied by using a [CSS class fallback](#css-class-fallback). +The `prefers-color-scheme` media query is supported by [all modern browsers](https://caniuse.com/#feat=prefers-color-scheme). Users will not be able to benefit from having the dark theme applied using this media query in certain browsers, however, the dark theme can still be applied by using a [CSS class fallback](#css-class-fallback) if support for older browsers is needed. ## CSS Class Fallback @@ -53,7 +51,7 @@ Notice that the variables should be in both places in this example. We can [use ## Combining with JavaScript -In order to keep the CSS variables written once and avoid having to update them in multiple places, the fallback and class can be combined by using JavaScript to check the value of the `prefers-color-scheme` media query and adding the `dark` class if the preference is `dark`. Here's what the CSS would look like: +In order to keep the CSS variables written once and avoid having to update them in multiple places, the `dark` class can be added when the value of the `prefers-color-scheme` media query is `dark`. Here's what the CSS would look like: ```css body.dark { @@ -65,63 +63,27 @@ Notice that the variables above are only in the `body.dark` selector now, and th ### Automatically Enable Dark Mode -In the JavaScript, the `dark` class can be added to the `` by checking if the document matches the media query using [matchMedia()](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia). This will enable dark mode to still work based on the user preference. - -```javascript -// Use matchMedia to check the user preference -const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); - -toggleDarkTheme(prefersDark.matches); - -// Listen for changes to the prefers-color-scheme media query -prefersDark.addEventListener('change', (mediaQuery) => toggleDarkTheme(mediaQuery.matches)); - -// Add or remove the "dark" class based on if the media query matches -function toggleDarkTheme(shouldAdd) { - document.body.classList.toggle('dark', shouldAdd); -} -``` +The `dark` class can be added to the `` by checking if the document matches the media query using [matchMedia()](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia). This will allow dark mode to still work based on the user's preference. :::note -Tip: make sure to view the Codepen below in a [supported browser](https://caniuse.com/#feat=prefers-color-scheme) and then try changing the system preferences on your device between light & dark mode. Here's [how to enable dark mode on Windows 10](https://blogs.windows.com/windowsexperience/2016/08/08/windows-10-tip-personalize-your-pc-by-enabling-the-dark-theme/) and [how to enable it on a Mac](https://support.apple.com/en-us/HT208976). +The demo below prioritizes the site's theme over the system settings. If your system settings are set to something other than the site's theme when the demo loads, it will match the site's theme. Try changing the system preferences on your device between light & dark mode to see it change. ::: - - - - -### Manually Toggle Dark Mode - -In addition to calling `toggleDarkTheme()` when the app loads and when the media query changes, the `toggleDarkTheme()` function could be called by the app, such as when a user changes a toggle, to switch between the light and dark themes: - -```javascript -// Query for the toggle that is used to change between themes -const toggle = document.querySelector('#themeToggle'); - -// Listen for the toggle check/uncheck to toggle the dark class on the -toggle.addEventListener('ionChange', (ev) => { - document.body.classList.toggle('dark', ev.detail.checked); -}); +:::info +Not sure how to change the system settings? Here's [how to enable dark mode on Windows 11](https://support.microsoft.com/en-us/windows/change-colors-in-windows-d26ef4d6-819a-581c-1581-493cfcc005fe) and [how to enable it on a Mac](https://support.apple.com/en-us/HT208976). +::: -const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); +import AutomaticDarkMode from '@site/static/usage/v7/theming/automatic-dark-mode/index.md'; -// Listen for changes to the prefers-color-scheme media query -prefersDark.addEventListener('change', (e) => checkToggle(e.matches)); + -// Called when the app loads -function loadApp() { - checkToggle(prefersDark.matches); -} +### Manually Toggle Dark Mode -// Called by the media query to check/uncheck the toggle -function checkToggle(shouldCheck) { - toggle.checked = shouldCheck; -} -``` +In addition to adding the `dark` class to the `` when the media query changes, the class can be added by the app, such as when a user changes a toggle, to switch between the light and dark themes: - +import ManualDarkMode from '@site/static/usage/v7/theming/manual-dark-mode/index.md'; - + ## Adjusting System UI Components @@ -158,170 +120,171 @@ For developers looking to customize the theme color under the status bar in Safa Ionic has a recommended theme for variables to use in order to get a dark mode based on the device running the app. It can be broken down into the following parts: 1. Changing the default [Ionic colors](colors.md) for all [modes](platform-styles.md#ionic-modes) to complement the dark background in the `body.dark` selector. -1. Setting variables for the dark theme on `ios` devices. -1. Setting variables for the dark theme on `md` devices. +2. Setting variables for the dark theme on `ios` devices. +3. Setting variables for the dark theme on `md` devices. -The following code can be copied and pasted into an app to get Ionic's dark theme. We add the `dark` class to the document body using JavaScript as mentioned in the [combining with JavaScript](#combining-with-javascript) section. The dark mode will not be enabled until the `dark` class is added to the document body. +The following code can be copied and pasted into an app's global CSS file to get Ionic's dark theme. We are [using the CSS media query](#using-media-queries) to enable dark mode. If older browser support is required, use the method described in the [combining with JavaScript](#combining-with-javascript) section. -:::note +:::info For more information on the variables that are being changed, including other variables that can be added to further customize, see [Themes](themes.md). ::: ```css -/* - * Dark Colors - * ------------------------------------------- - */ - -body.dark { - --ion-color-primary: #428cff; - --ion-color-primary-rgb: 66, 140, 255; - --ion-color-primary-contrast: #ffffff; - --ion-color-primary-contrast-rgb: 255, 255, 255; - --ion-color-primary-shade: #3a7be0; - --ion-color-primary-tint: #5598ff; - - --ion-color-secondary: #50c8ff; - --ion-color-secondary-rgb: 80, 200, 255; - --ion-color-secondary-contrast: #ffffff; - --ion-color-secondary-contrast-rgb: 255, 255, 255; - --ion-color-secondary-shade: #46b0e0; - --ion-color-secondary-tint: #62ceff; - - --ion-color-tertiary: #6a64ff; - --ion-color-tertiary-rgb: 106, 100, 255; - --ion-color-tertiary-contrast: #ffffff; - --ion-color-tertiary-contrast-rgb: 255, 255, 255; - --ion-color-tertiary-shade: #5d58e0; - --ion-color-tertiary-tint: #7974ff; - - --ion-color-success: #2fdf75; - --ion-color-success-rgb: 47, 223, 117; - --ion-color-success-contrast: #000000; - --ion-color-success-contrast-rgb: 0, 0, 0; - --ion-color-success-shade: #29c467; - --ion-color-success-tint: #44e283; - - --ion-color-warning: #ffd534; - --ion-color-warning-rgb: 255, 213, 52; - --ion-color-warning-contrast: #000000; - --ion-color-warning-contrast-rgb: 0, 0, 0; - --ion-color-warning-shade: #e0bb2e; - --ion-color-warning-tint: #ffd948; - - --ion-color-danger: #ff4961; - --ion-color-danger-rgb: 255, 73, 97; - --ion-color-danger-contrast: #ffffff; - --ion-color-danger-contrast-rgb: 255, 255, 255; - --ion-color-danger-shade: #e04055; - --ion-color-danger-tint: #ff5b71; - - --ion-color-dark: #f4f5f8; - --ion-color-dark-rgb: 244, 245, 248; - --ion-color-dark-contrast: #000000; - --ion-color-dark-contrast-rgb: 0, 0, 0; - --ion-color-dark-shade: #d7d8da; - --ion-color-dark-tint: #f5f6f9; - - --ion-color-medium: #989aa2; - --ion-color-medium-rgb: 152, 154, 162; - --ion-color-medium-contrast: #000000; - --ion-color-medium-contrast-rgb: 0, 0, 0; - --ion-color-medium-shade: #86888f; - --ion-color-medium-tint: #a2a4ab; - - --ion-color-light: #222428; - --ion-color-light-rgb: 34, 36, 40; - --ion-color-light-contrast: #ffffff; - --ion-color-light-contrast-rgb: 255, 255, 255; - --ion-color-light-shade: #1e2023; - --ion-color-light-tint: #383a3e; -} +@media (prefers-color-scheme: dark) { + /* + * Dark Colors + * ------------------------------------------- + */ + + body { + --ion-color-primary: #428cff; + --ion-color-primary-rgb: 66, 140, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47, 223, 117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255, 213, 52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34, 36, 40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255, 255, 255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; + } -/* - * iOS Dark Theme - * ------------------------------------------- - */ - -.ios body.dark { - --ion-background-color: #000000; - --ion-background-color-rgb: 0, 0, 0; - - --ion-text-color: #ffffff; - --ion-text-color-rgb: 255, 255, 255; - - --ion-color-step-50: #0d0d0d; - --ion-color-step-100: #1a1a1a; - --ion-color-step-150: #262626; - --ion-color-step-200: #333333; - --ion-color-step-250: #404040; - --ion-color-step-300: #4d4d4d; - --ion-color-step-350: #595959; - --ion-color-step-400: #666666; - --ion-color-step-450: #737373; - --ion-color-step-500: #808080; - --ion-color-step-550: #8c8c8c; - --ion-color-step-600: #999999; - --ion-color-step-650: #a6a6a6; - --ion-color-step-700: #b3b3b3; - --ion-color-step-750: #bfbfbf; - --ion-color-step-800: #cccccc; - --ion-color-step-850: #d9d9d9; - --ion-color-step-900: #e6e6e6; - --ion-color-step-950: #f2f2f2; - - --ion-item-background: #000000; - - --ion-card-background: #1c1c1d; -} + /* + * iOS Dark Theme + * ------------------------------------------- + */ + + .ios body { + --ion-background-color: #000000; + --ion-background-color-rgb: 0, 0, 0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #000000; + + --ion-card-background: #1c1c1d; + } -.ios body.dark ion-modal { - --ion-background-color: var(--ion-color-step-100); - --ion-toolbar-background: var(--ion-color-step-150); - --ion-toolbar-border-color: var(--ion-color-step-250); - --ion-item-background: var(--ion-color-step-150); -} + .ios ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); + } -/* - * Material Design Dark Theme - * ------------------------------------------- - */ - -.md body.dark { - --ion-background-color: #121212; - --ion-background-color-rgb: 18, 18, 18; - - --ion-text-color: #ffffff; - --ion-text-color-rgb: 255, 255, 255; - - --ion-border-color: #222222; - - --ion-color-step-50: #1e1e1e; - --ion-color-step-100: #2a2a2a; - --ion-color-step-150: #363636; - --ion-color-step-200: #414141; - --ion-color-step-250: #4d4d4d; - --ion-color-step-300: #595959; - --ion-color-step-350: #656565; - --ion-color-step-400: #717171; - --ion-color-step-450: #7d7d7d; - --ion-color-step-500: #898989; - --ion-color-step-550: #949494; - --ion-color-step-600: #a0a0a0; - --ion-color-step-650: #acacac; - --ion-color-step-700: #b8b8b8; - --ion-color-step-750: #c4c4c4; - --ion-color-step-800: #d0d0d0; - --ion-color-step-850: #dbdbdb; - --ion-color-step-900: #e7e7e7; - --ion-color-step-950: #f3f3f3; - - --ion-item-background: #1e1e1e; - - --ion-toolbar-background: #1f1f1f; - - --ion-tab-bar-background: #1f1f1f; - - --ion-card-background: #1e1e1e; + /* + * Material Design Dark Theme + * ------------------------------------------- + */ + + .md body { + --ion-background-color: #121212; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; + } } ``` diff --git a/static/usage/v7/theming/automatic-dark-mode/angular/example_component_html.md b/static/usage/v7/theming/automatic-dark-mode/angular/example_component_html.md new file mode 100644 index 00000000000..418eddfc30f --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/angular/example_component_html.md @@ -0,0 +1,45 @@ +```html + + + + + + Display + + + + + + + + + + Appearance + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/angular/example_component_ts.md b/static/usage/v7/theming/automatic-dark-mode/angular/example_component_ts.md new file mode 100644 index 00000000000..add5097b954 --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/angular/example_component_ts.md @@ -0,0 +1,24 @@ +```ts +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-example', + templateUrl: 'example.component.html', +}) +export class ExampleComponent implements OnInit { + ngOnInit() { + // Use matchMedia to check the user preference + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); + + this.toggleDarkTheme(prefersDark.matches); + + // Listen for changes to the prefers-color-scheme media query + prefersDark.addEventListener('change', (mediaQuery) => this.toggleDarkTheme(mediaQuery.matches)); + } + + // Add or remove the "dark" class on the document body + toggleDarkTheme(shouldAdd) { + document.body.classList.toggle('dark', shouldAdd); + } +} +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/angular/global_css.md b/static/usage/v7/theming/automatic-dark-mode/angular/global_css.md new file mode 100644 index 00000000000..e26327f896f --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/angular/global_css.md @@ -0,0 +1,25 @@ +```css +/* + * Optional CSS + * ----------------------------------- + */ + +/* This sets a different background and item background in light mode on ios */ +.ios body { + --ion-background-color: #f2f2f6; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This sets a different background and item background in light mode on md */ +.md body { + --ion-background-color: #f9f9f9; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This is added for the flashing that happens when toggling between themes */ +ion-item { + --transition: none; +} +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/demo.html b/static/usage/v7/theming/automatic-dark-mode/demo.html new file mode 100644 index 00000000000..17acbcf3fe6 --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/demo.html @@ -0,0 +1,104 @@ + + + + + + Theming + + + + + + + + + + + + + + Display + + + + + + + + + + Appearance + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + + + + + + + + diff --git a/static/usage/v7/theming/automatic-dark-mode/index.md b/static/usage/v7/theming/automatic-dark-mode/index.md new file mode 100644 index 00000000000..6e6b490de6f --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/index.md @@ -0,0 +1,50 @@ +import Playground from '@site/src/components/global/Playground'; + +import javascript_index_html from './javascript.md'; + +import react_main_tsx from './react/main_tsx.md'; +import react_main_css from './react/main_css.md'; + +import vue from './vue.md'; + +import angular_example_component_html from './angular/example_component_html.md'; +import angular_example_component_ts from './angular/example_component_ts.md'; +import angular_global_css from './angular/global_css.md'; + +import variables_css from './theme/variables_css.md'; + + diff --git a/static/usage/v7/theming/automatic-dark-mode/javascript.md b/static/usage/v7/theming/automatic-dark-mode/javascript.md new file mode 100644 index 00000000000..9e65673ba8d --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/javascript.md @@ -0,0 +1,105 @@ +```html + + + + + + + + + + + + + + + + Display + + + + + + + + + + Appearance + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + + + + + + + + +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/react/main_css.md b/static/usage/v7/theming/automatic-dark-mode/react/main_css.md new file mode 100644 index 00000000000..e26327f896f --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/react/main_css.md @@ -0,0 +1,25 @@ +```css +/* + * Optional CSS + * ----------------------------------- + */ + +/* This sets a different background and item background in light mode on ios */ +.ios body { + --ion-background-color: #f2f2f6; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This sets a different background and item background in light mode on md */ +.md body { + --ion-background-color: #f9f9f9; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This is added for the flashing that happens when toggling between themes */ +ion-item { + --transition: none; +} +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/react/main_tsx.md b/static/usage/v7/theming/automatic-dark-mode/react/main_tsx.md new file mode 100644 index 00000000000..dc92e1ad1cf --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/react/main_tsx.md @@ -0,0 +1,93 @@ +```tsx +import React, { useEffect } from 'react'; +import { + IonBackButton, + IonButton, + IonButtons, + IonContent, + IonHeader, + IonIcon, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonRange, + IonText, + IonTitle, + IonToggle, + IonToolbar, +} from '@ionic/react'; +import { personCircle, personCircleOutline, sunny, sunnyOutline } from 'ionicons/icons'; + +import './main.css'; + +function Example() { + // Add or remove the "dark" class on the document body + const toggleDarkTheme = (shouldAdd: boolean) => { + document.body.classList.toggle('dark', shouldAdd); + }; + + useEffect(() => { + // Use matchMedia to check the user preference + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); + + toggleDarkTheme(prefersDark.matches); + + // Listen for changes to the prefers-color-scheme media query + prefersDark.addEventListener('change', (mediaQuery) => toggleDarkTheme(mediaQuery.matches)); + }, []); + + return ( + <> + + + + + + Display + + + + + + + + + + Appearance + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + + True Tone + + + + + + + Night Shift + + 9:00 PM to 8:00 AM + + + + + + ); +} +export default Example; +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/theme/variables_css.md b/static/usage/v7/theming/automatic-dark-mode/theme/variables_css.md new file mode 100644 index 00000000000..72a10e6d263 --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/theme/variables_css.md @@ -0,0 +1,160 @@ +```css +/* Ionic Variables and Theming. For more info, please see: +http://ionicframework.com/docs/theming/ */ + +/* + * Dark Colors + * ------------------------------------------- + */ + +body.dark { + --ion-color-primary: #428cff; + --ion-color-primary-rgb: 66, 140, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47, 223, 117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255, 213, 52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34, 36, 40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255, 255, 255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; +} + +/* + * iOS Dark Theme + * ------------------------------------------- + */ + +.ios body.dark { + --ion-background-color: #000000; + --ion-background-color-rgb: 0, 0, 0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #1c1c1d; + + --ion-card-background: #1c1c1d; +} + +.ios body.dark ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); +} + +/* + * Material Design Dark Theme + * ------------------------------------------- + */ + +.md body.dark { + --ion-background-color: #121212; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; +} +``` diff --git a/static/usage/v7/theming/automatic-dark-mode/vue.md b/static/usage/v7/theming/automatic-dark-mode/vue.md new file mode 100644 index 00000000000..45dd5f8d9a5 --- /dev/null +++ b/static/usage/v7/theming/automatic-dark-mode/vue.md @@ -0,0 +1,129 @@ +```html + + + + + +``` diff --git a/static/usage/v7/theming/manual-dark-mode/angular/example_component_html.md b/static/usage/v7/theming/manual-dark-mode/angular/example_component_html.md new file mode 100644 index 00000000000..855a77e99a8 --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/angular/example_component_html.md @@ -0,0 +1,53 @@ +```html + + + + + + Display + + + + + + + + + + Appearance + + + Dark Mode + + + + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + +``` diff --git a/static/usage/v7/theming/manual-dark-mode/angular/example_component_ts.md b/static/usage/v7/theming/manual-dark-mode/angular/example_component_ts.md new file mode 100644 index 00000000000..ad697b08012 --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/angular/example_component_ts.md @@ -0,0 +1,39 @@ +```ts +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-example', + templateUrl: 'example.component.html', +}) +export class ExampleComponent implements OnInit { + themeToggle = false; + + ngOnInit() { + // Use matchMedia to check the user preference + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); + + // Initialize the dark theme based on the initial + // value of the prefers-color-scheme media query + this.initializeDarkTheme(prefersDark.matches); + + // Listen for changes to the prefers-color-scheme media query + prefersDark.addEventListener('change', (mediaQuery) => this.initializeDarkTheme(mediaQuery.matches)); + } + + // Check/uncheck the toggle and update the theme based on isDark + initializeDarkTheme(isDark) { + this.themeToggle = isDark; + this.toggleDarkTheme(isDark); + } + + // Listen for the toggle check/uncheck to toggle the dark theme + toggleChange(ev) { + this.toggleDarkTheme(ev.detail.checked); + } + + // Add or remove the "dark" class on the document body + toggleDarkTheme(shouldAdd) { + document.body.classList.toggle('dark', shouldAdd); + } +} +``` diff --git a/static/usage/v7/theming/manual-dark-mode/angular/global_css.md b/static/usage/v7/theming/manual-dark-mode/angular/global_css.md new file mode 100644 index 00000000000..e26327f896f --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/angular/global_css.md @@ -0,0 +1,25 @@ +```css +/* + * Optional CSS + * ----------------------------------- + */ + +/* This sets a different background and item background in light mode on ios */ +.ios body { + --ion-background-color: #f2f2f6; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This sets a different background and item background in light mode on md */ +.md body { + --ion-background-color: #f9f9f9; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This is added for the flashing that happens when toggling between themes */ +ion-item { + --transition: none; +} +``` diff --git a/static/usage/v7/theming/manual-dark-mode/demo.html b/static/usage/v7/theming/manual-dark-mode/demo.html new file mode 100644 index 00000000000..c4d502db12d --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/demo.html @@ -0,0 +1,136 @@ + + + + + + Theming + + + + + + + + + + + + + + Display + + + + + + + + + + Appearance + + + Dark Mode + + + + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + + + + + + + + diff --git a/static/usage/v7/theming/manual-dark-mode/index.md b/static/usage/v7/theming/manual-dark-mode/index.md new file mode 100644 index 00000000000..2022b7e8952 --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/index.md @@ -0,0 +1,50 @@ +import Playground from '@site/src/components/global/Playground'; + +import javascript_index_html from './javascript.md'; + +import react_main_tsx from './react/main_tsx.md'; +import react_main_css from './react/main_css.md'; + +import vue from './vue.md'; + +import angular_example_component_html from './angular/example_component_html.md'; +import angular_example_component_ts from './angular/example_component_ts.md'; +import angular_global_css from './angular/global_css.md'; + +import variables_css from './theme/variables_css.md'; + + diff --git a/static/usage/v7/theming/manual-dark-mode/javascript.md b/static/usage/v7/theming/manual-dark-mode/javascript.md new file mode 100644 index 00000000000..0b01544ae9b --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/javascript.md @@ -0,0 +1,132 @@ +```html + + + + + + + + + + + + + + + + Display + + + + + + + + + + Appearance + + + Dark Mode + + + + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + True Tone + + + + + + Night Shift + 9:00 PM to 8:00 AM + + + + + + + + + + +``` diff --git a/static/usage/v7/theming/manual-dark-mode/react/main_css.md b/static/usage/v7/theming/manual-dark-mode/react/main_css.md new file mode 100644 index 00000000000..e26327f896f --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/react/main_css.md @@ -0,0 +1,25 @@ +```css +/* + * Optional CSS + * ----------------------------------- + */ + +/* This sets a different background and item background in light mode on ios */ +.ios body { + --ion-background-color: #f2f2f6; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This sets a different background and item background in light mode on md */ +.md body { + --ion-background-color: #f9f9f9; + --ion-toolbar-background: var(--ion-background-color); + --ion-item-background: #fff; +} + +/* This is added for the flashing that happens when toggling between themes */ +ion-item { + --transition: none; +} +``` diff --git a/static/usage/v7/theming/manual-dark-mode/react/main_tsx.md b/static/usage/v7/theming/manual-dark-mode/react/main_tsx.md new file mode 100644 index 00000000000..70938e6a804 --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/react/main_tsx.md @@ -0,0 +1,117 @@ +```tsx +import React, { useEffect, useState } from 'react'; +import { + IonBackButton, + IonButton, + IonButtons, + IonContent, + IonHeader, + IonIcon, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonRange, + IonText, + IonTitle, + IonToggle, + IonToolbar, +} from '@ionic/react'; +import type { ToggleCustomEvent } from '@ionic/react'; +import { personCircle, personCircleOutline, sunny, sunnyOutline } from 'ionicons/icons'; + +import './main.css'; + +function Example() { + const [themeToggle, setThemeToggle] = useState(false); + + // Listen for the toggle check/uncheck to toggle the dark theme + const toggleChange = (ev: ToggleCustomEvent) => { + toggleDarkTheme(ev.detail.checked); + }; + + // Add or remove the "dark" class on the document body + const toggleDarkTheme = (shouldAdd: boolean) => { + document.body.classList.toggle('dark', shouldAdd); + }; + + // Check/uncheck the toggle and update the theme based on isDark + const initializeDarkTheme = (isDark: boolean) => { + setThemeToggle(isDark); + toggleDarkTheme(isDark); + }; + + useEffect(() => { + // Use matchMedia to check the user preference + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); + + // Initialize the dark theme based on the initial + // value of the prefers-color-scheme media query + initializeDarkTheme(prefersDark.matches); + + // Listen for changes to the prefers-color-scheme media query + prefersDark.addEventListener('change', (mediaQuery) => initializeDarkTheme(mediaQuery.matches)); + }, []); + + return ( + <> + + + + + + Display + + + + + + + + + + Appearance + + + + Dark Mode + + + + + + Text Size + + Bold Text + + + + Brightness + + + + + + + + + + True Tone + + + + + + + Night Shift + + 9:00 PM to 8:00 AM + + + + + + ); +} +export default Example; +``` diff --git a/static/usage/v7/theming/manual-dark-mode/theme/variables_css.md b/static/usage/v7/theming/manual-dark-mode/theme/variables_css.md new file mode 100644 index 00000000000..72a10e6d263 --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/theme/variables_css.md @@ -0,0 +1,160 @@ +```css +/* Ionic Variables and Theming. For more info, please see: +http://ionicframework.com/docs/theming/ */ + +/* + * Dark Colors + * ------------------------------------------- + */ + +body.dark { + --ion-color-primary: #428cff; + --ion-color-primary-rgb: 66, 140, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47, 223, 117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255, 213, 52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34, 36, 40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255, 255, 255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; +} + +/* + * iOS Dark Theme + * ------------------------------------------- + */ + +.ios body.dark { + --ion-background-color: #000000; + --ion-background-color-rgb: 0, 0, 0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #1c1c1d; + + --ion-card-background: #1c1c1d; +} + +.ios body.dark ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); +} + +/* + * Material Design Dark Theme + * ------------------------------------------- + */ + +.md body.dark { + --ion-background-color: #121212; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; +} +``` diff --git a/static/usage/v7/theming/manual-dark-mode/vue.md b/static/usage/v7/theming/manual-dark-mode/vue.md new file mode 100644 index 00000000000..2dfda3aa30c --- /dev/null +++ b/static/usage/v7/theming/manual-dark-mode/vue.md @@ -0,0 +1,162 @@ +```html + + + + + +```