From 2d8f6a7c70c9fb6be2a8bb8f1e3cacce2321a6be Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:28:57 -0500 Subject: [PATCH] docs(core): add guidelines for naming CSS shadow parts --- docs/README.md | 1 + docs/component-guide.md | 10 ++ docs/sass-guidelines.md | 1 + docs/shadow-parts-guidelines.md | 291 ++++++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 docs/shadow-parts-guidelines.md diff --git a/docs/README.md b/docs/README.md index 85cbbc9422d..bd2021581ce 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,6 +23,7 @@ It is based on Web Componen | [Contributing](./CONTRIBUTING.md) | How to contribute including creating pull requests, commit message guidelines, and more. | | [Component Guide](./component-guide.md) | Guidelines for implementing component states, accessibility, and more. | | [Sass Guidelines](./sass-guidelines.md) | Outlines scenarios where Sass members and comments should be used. | +| [CSS Shadow Parts Guidelines](./shadow-parts-guidelines.md) | Guidelines for CSS shadow parts in components. | ## Packages diff --git a/docs/component-guide.md b/docs/component-guide.md index 03b3ab9f761..6f72aeec110 100644 --- a/docs/component-guide.md +++ b/docs/component-guide.md @@ -17,6 +17,8 @@ * [Example Components](#example-components-4) * [Component Structure](#component-structure-1) - [Converting Scoped to Shadow](#converting-scoped-to-shadow) +- [Sass Variables](#sass-variables) +- [CSS Shadow Parts](#css-shadow-parts) - [RTL](#rtl) - [Adding New Components with Native Input Support](#adding-new-components-with-native-input-support) * [Angular Integration](#angular-integration) @@ -722,6 +724,14 @@ There will be some CSS issues when converting to shadow. Below are some of the d :host-context(ion-toolbar:not(.ion-color)):host(:not(.ion-color)) ::slotted(ion-segment-button) { ``` +## Sass Variables + +For guidelines on when to use Sass Variables, see the [Sass Guidelines](./sass-guidelines.md). + +## CSS Shadow Parts + +For guidelines on adding CSS shadow parts, see the [CSS Shadow Parts Guidelines](./shadow-parts-guidelines.md). + ## RTL When you need to support both LTR and RTL modes, try to avoid using values such as `left` and `right`. For certain CSS properties, you can use the appropriate mixin to have this handled for you automatically. diff --git a/docs/sass-guidelines.md b/docs/sass-guidelines.md index d48d496df54..3b3e104fd23 100644 --- a/docs/sass-guidelines.md +++ b/docs/sass-guidelines.md @@ -1,5 +1,6 @@ # Sass Guidelines +TABLE OF CONTENTS - [Definitions](#definitions) - [Scope](#scope) - [Historical Usage](#historical-usage) diff --git a/docs/shadow-parts-guidelines.md b/docs/shadow-parts-guidelines.md new file mode 100644 index 00000000000..9ee691ef8e5 --- /dev/null +++ b/docs/shadow-parts-guidelines.md @@ -0,0 +1,291 @@ +# CSS Shadow Parts Guidelines + +TABLE OF CONTENTS +- [Definitions](#definitions) +- [Scope](#scope) +- [General Guidelines](#general-guidelines) +- [Standard Parts](#standard-parts) +- [Specialized Parts](#specialized-parts) +- [Documentation](#documentation) + +## Definitions + +**CSS Shadow Parts:** The CSS shadow parts module defines the [::part()](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/::part) pseudo-element that can be set on a [shadow host](https://developer.mozilla.org/en-US/docs/Glossary/Shadow_tree). Using this pseudo-element, you can enable shadow hosts to expose the selected element in the shadow tree to the outside page for styling purposes. [^1] + +## Scope + +Ionic Framework components that use Shadow DOM expose CSS Shadow Parts to enable custom styling by end users. + +This document establishes a standardized naming convention for CSS Shadow Parts in Ionic Framework components. + +## General Guidelines + +1. **Attempt to use standard parts first**: Use `native`, `inner`, `content`, and `container` wherever they apply before inventing new names. +2. **Use semantic, kebab-case names**: Choose descriptive names that communicate the role of the element (for example, `detail-icon`, `supporting-text`). +3. **Reuse names for the same concept**: Use the same part name across components when the element serves the same role (for example, `backdrop`, `handle`, `label`). + +## Standard Parts + +### `native` + +The native HTML element (button, anchor, or div) that wraps all child elements. + +- **Use when**: Component renders a native HTML element +- **Examples**: `ion-button`, `ion-item`, `ion-card` +- **Code examples**: + ```tsx + // Back Button - Always renders a button tag + return ( + + + + ); + ``` + + ```tsx + // Breadcrumb - Checks if href is set to determine the native tag type + const TagType = this.href === undefined ? 'span' : 'a'; + + return ( + + + + + + + + ); + ``` + +### `inner` + +The inner container element that wraps the component's content structure. + +- **Use when**: You need a structural inner container that doesn't necessarily wrap slots or user-visible content +- **Examples**: `ion-item`, `ion-item-divider`, `ion-item-option`, `ion-list-header` +- **Code examples**: + ```tsx + // Item + return ( + + + + ); + ``` + + ```tsx + // Item Divider + return ( + + +
+
+ +
+ +
+
+ ); + ``` + + ```tsx + // Item Option + return ( + + + + ); + ``` + + ```tsx + // List Header + return ( + +
+ +
+
+ ); + ``` + +### `content` + +The wrapper element for the default slot (or a semantically named `content` slot). + +- **Use when**: Wrapping the default slot or semantically named content slot +- **Examples**: `ion-item`, `ion-item-divider`, `ion-popover`, `ion-modal`, `ion-accordion` +- **Code examples**: + ```tsx + // Item - Wraps only the default slot + return ( + + + + ); + ``` + + ```tsx + // Accordion - Wraps the named "content" slot + return ( + + + +
+
+ +
+
+
+ ); + ``` + + ```tsx + // Toolbar - Coexists with other slots at the same level + return ( + +
+
+ + +
+ +
+ + +
+
+ ); + ``` + +### `container` + +A wrapper element that contains multiple slots, multiple rendered elements, or specialized parts. + +- **Use when**: Wrapping multiple slots together, multiple rendered elements, or specialized parts +- **Don't use when**: Wrapping only the default slot (use `content` instead) +- **Examples**: `ion-item-option` (multiple slots), `ion-toolbar` (multiple slots), `ion-toast` (multiple elements), `ion-checkbox` (specialized parts) +- **Code examples**: + ```tsx + // Toolbar - Wraps multiple slots together + return ( + +
+
+ + +
+ +
+ + +
+
+ ); + ``` + + ```tsx + // Select - Wraps multiple rendered elements + return ( + + + + ); + ``` + + ```tsx + // Checkbox - Wraps specialized parts + return ( + + + + ); + ``` + +## Specialized Parts + +Components may also expose specialized parts for specific elements. The following parts are reused across multiple components: + +| Name | Description | +| --- | --- | +| `background` | Background elements (e.g., `ion-content`, `ion-toolbar`) | +| `backdrop` | Backdrop elements. **Must only be used on `` components.** (e.g., `ion-modal`, `ion-popover`, `ion-menu`) | +| `label` | Label text elements | +| `supporting-text` | Supporting text elements | +| `helper-text` | Helper text elements | +| `error-text` | Error text elements | +| `icon` | Icon elements. **Must only be used on `` components.** Use specific names like `detail-icon`, `close-icon` when the icon serves a distinct purpose (e.g., `ion-item` uses `detail-icon`, `ion-fab-button` uses `close-icon`) | +| `handle` | Handle elements (e.g., `ion-modal`, `ion-toggle`) | +| `track` | Track elements (e.g., `ion-toggle`, `ion-progress-bar`) | +| `mark` | Checkmark or indicator marks (e.g., `ion-checkbox`, `ion-radio`) | + +**When to create new specialized parts:** +- Use standard parts (`native`, `inner`, `content`, `container`) when they apply +- Reuse existing specialized parts (listed above) when they match the element's role +- Create component-specific specialized parts for elements that don't fit standard patterns or existing specialized parts +- Use descriptive, semantic names (e.g., `header`, `text`, `arrow`, `scroll` for component-specific elements) + +## Documentation + +Shadow parts must be documented in the component's JSDoc comments using the `@part` tag. The following example demonstrates the proper documentation format: + +```tsx +/** + * @part native - The native HTML button, anchor or div element that wraps all child elements. + * @part inner - The inner container element that wraps the item content. + * @part content - The wrapper element that contains the default slot. + * @part detail-icon - The chevron icon for the item. Only applies when `detail="true"`. + */ +``` + +[^1]: MDN Documentation - CSS shadow parts, https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Shadow_parts