Part and Exportparts for External Styling
Expose shadow DOM parts to external CSS with part and exportparts.
Part and Exportparts for External Styling is a free HTML Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Encapsulation Trade-off
Shadow DOM's strict style encapsulation prevents consumers from restyling individual elements inside a component. CSS variables work for global properties, but you cannot, for example, give the internal "close" button a custom border-radius. Parts solve this.
The part Attribute
Mark a shadow-internal element with part="name". Consumers can then target it with the ::part(name) pseudo-element: my-dialog::part(close-button) { color: red; }. The named element becomes a styling hook while the rest of the shadow stays encapsulated.
// Shadow tree:
<button part="close-button">×</button>
// Page CSS:
my-dialog::part(close-button) {
color: red;
border-radius: 50%;
}Multiple Parts on One Element
Space-separate names to expose one element as multiple parts: part="button primary". ::part(button) targets it generically, ::part(primary) targets it as a primary-style element. Each name is matched independently.
::part Limitations
::part only allows certain pseudo-classes (:hover, :focus, :disabled) — not descendant combinators or further structural selection. ::part(card) p is invalid; you cannot reach inside a part with descendant selectors.
exportparts Forwards Parts
When a custom element nests another custom element inside its own shadow, the inner element's parts are normally not exposed to the outer page. exportparts="close-button" on the nested element forwards those parts up to the outer host.
// Outer shadow:
<inner-element exportparts="close-button"></inner-element>
// Page:
outer-element::part(close-button) { color: red; }Renaming When Exporting
exportparts="close-button: dismiss" exports the inner part as a new name on the outer element. This lets the outer component present a clean naming surface independent of which internal elements it composes.
parts vs CSS Custom Properties
Custom properties expose values (color, spacing, fonts). Parts expose elements (full CSS surface — borders, transforms, animations). Use custom properties for global tokens and parts for one-off element-level customization. Both can coexist on the same component.
Theming Pattern
Design system practice: expose a small surface of parts for the most-customized elements (buttons, headers, indicators) plus a generous set of custom properties for color, spacing and typography. Consumers can theme either at the value level or the element level depending on their need.
Stability of Part Names
Part names become part of the component's public API — changing them breaks consumer CSS. Pick names that describe the element's role ("close-button", "header", "track") rather than its position ("first-button") so the API stays meaningful as the implementation evolves.
Documentation Hints
List all available parts (and exported parts) in the component's readme. Without documentation, consumers must inspect the DOM to discover parts, which couples them to whatever they happen to find. Treat the parts list like the props list of a framework component.
Browser Support
::part and exportparts ship in all modern browsers. Even older Safari versions support ::part now. Use freely; for very old browsers (mostly defunct), fall back to additional CSS custom properties as a workaround.
Knowledge Check
What does the exportparts attribute do?
Summary
The part attribute exposes individual shadow elements for external styling via ::part(name) — full CSS power without breaking encapsulation. exportparts forwards parts from nested custom elements up to the outer host, optionally renaming. Combine parts with CSS custom properties for a complete theming surface, and document the part list as part of the component API.
Frequently asked questions
Is the “Part and Exportparts for External Styling” lesson free?
Yes — the full text of “Part and Exportparts for External Styling” is free to read here on the web, and the HTML Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the HTML Academy course, upgrade to CoddyKit PRO.
What will I learn in “Part and Exportparts for External Styling”?
Expose shadow DOM parts to external CSS with part and exportparts. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start HTML Academy?
No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Part and Exportparts for External Styling” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this HTML Academy lesson?
Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- attachShadow and Shadow Root
- Slot Elements for Content Distribution
- Scoped Styles Inside Shadow DOM
- Part and Exportparts for External Styling