NV Elements Catalog Starters Repo System Themes About Getting Started Changelog Metrics Support Accessibility Contributions Requests Migration Deprecations Integrations Installation MCP CLI Lint Angular Bundles Extensions Go Hugo Import Maps Lit NextJS Nuxt Preact React SolidJS Svelte TypeScript Vue Foundations Typography Iconography Themes Design Tokens Size & Space Objects Interactions Support Status Color Animation Fonts Layers Custom Layout Horizontal Vertical Grid Popovers i18n Visualization View Transitions Elements Accordion Alert Avatar Badge Breadcrumb Button Button Group Card Chat Message Checkbox Color Combobox Copy Button Datagrid Integrations Column Action Column Alignment Column Fixed Column width Container Card Display Settings Footer Heatmap Keynav Multi Select Pagination Panel Detail Panel Grid Performance Placeholder Row Action Row Groups Row Sort Scroll Height Single Select Stripe Date Datetime Dialog Divider Dot Drawer Dropdown Dropdown Group Dropzone File Forms Validation Actions Control Icon Icon Button Input Input Group Logo Menu Month Notification Page Page Header Page Loader Pagination Panel Progressive Filter Chip Progress Bar Progress Ring Password Preferences Input Pulse Radio Range Resize Handle Search Select Skeleton Sort Button Sparkline Star Rating Steps Switch Tabs Tag Textarea Time Toast Toggletip Toolbar Tooltip Tree Week Patterns Authentication Browse Dashboard Editor Empty States Heatmap Keyboard Shortcut Logging Media Onboarding Panel Responsive Search Subheader Trend Code Codeblock Monaco Input Diff Input Editor Diff Editor Problems Markdown Markdown CSS Utility Labs Responsive Layout Viewport Container Patterns Forms API Design Properties & Attributes Slots Registration CustomEvents Stateless Composition Styles Packaging Glossary Logs Internal Guidelines Agent Harness Documentation Examples TypeScript Testing Unit Testing Accessibility Testing Lighthouse Testing SSR Testing Visual Testing Troubleshooting Component Creation Internal Examples All Examples

Styles

Strategies

Three primary strategies control or adjust the look and feel of the system, each with distinct trade-offs.

Automatic (system): can adjust look/feel based on browser conditions with high confidence. For example, CSS container or style queries can report accurate states of the current UI.

  • relative scales
  • responsive elements

Explicit (consumer dev/designer): low confidence the system can predict precise usage but high confidence by the consumer developer/designer. These cases are context specific. For example, when to use a small button in a toolbar vs a large button for a call to action.

  • size properties/variants
  • status properties/variants
  • CSS custom property overrides

Theme (user): system nor the consumer dev/designer can predict users preferences. For example, user has system OS defined preferences or overrides for light and dark themes or zoom/typography sizing.

  • compact theme
  • light/dark theme

Custom Properties

Elements expose custom CSS properties that typically correspond to their native CSS properties, as shown in the table below. Some custom properties have no direct mappings to their native counterparts and the table indicates them by the absence of MDN documentation references.

Name Description --background MDN Documentation --gap MDN Documentation --status-color

Prefer exposing shorthand values. border: var(--border) rather than border-color: var(--border-color) as this gives more flexibility to the user without expanding the public API surface. When possible keep CSS Custom Property names simple and map them 1:1 to the native CSS property. This lowers the learning curve of the API and makes it consistent between other components within the library.

Do Don't

    

    

#REMOVED Host

The internal host element is a pattern that provides an API guard on the element. When styling a custom element, avoid applying styles other than basic display properties and custom properties to the host element. The more styles applied to the host, the easier a consumer can override and change the styles in unexpected ways.

Don't:


    

In this example, the app may style the element in unsupported or unpredictable ways. Custom style leaks like this make visual changes or migrations difficult for both the library authors and consumers.

To prevent internal style leakage, leverage a internal host element to apply styles and expose only the styles as needed to the public facing API.

Do:


    

By scoping the background and color to the internal-host element, only the public API of the exposed CSS Custom Properties can change the look and feel of the element.

State Properties

Leverage host selectors to customize the element visual state. This avoids expanding the public API of the element and enabling a single CSS representation of the component. Each visual variant is solely responsible for modifying the public API to reflect the appropriate state.

Do:


    

By modifying only a single set of Custom Properties the CSS specificity stays low and ensures that developers can theme any combination of visual states within the predictable public API.

With custom elements, the element tag is the scope for the design tokens. Element-specific design tokens are unnecessary and increase the surface area of the API and number of tokens to maintain.


    

Visual customizations and theming are now fully compatible throughout the public API of the CSS custom properties.

Don't:


    

In this example the subtle change of not assigning to the default host properties not only increase the CSS specificity but also make certain customizations/theming impossible without exposing extra CSS custom properties.

Design Tokens Usage

CSS Custom Properties defined on the host should use Design Tokens that appropriately describe the system's intent. CSS Custom Properties should not be explicitly named with the element name as this encourages inconsistency between elements rather than using the system's intent/purpose tokens. Leveraging State Properties for CSS custom properties, element specific design tokens are unnecessary and increase the surface area of the API and number of tokens to maintain. (see State Properties for more information)

Do Don't

    

    

🏁 Performance: leveraging design tokens with defined intent drastically reduces the amount of CSS bundled and maintained within the system.

Element Style APIs

For custom states and behaviors, styles can hook into the public API of a reflected or set attribute, examples include:

  • types status: error | success | warning
  • states expanded | selected | disabled
  • behaviors closable | draggable

    

Margins & Whitespace

Elements should not have any external margins or whitespace outside the bounds of the host element. Margins on a host element make assumptions about the layout that is external to their responsibility. A design token/layout system allows designers and developers to layout elements/utilities consistently and with explicit intent and constraint.

🏁 Performance: avoiding margins enables  CSS containment for better performance 🎓 Learn:  leading trim 🎓 Learn about  Capsize CSS

Logical Properties

Use CSS Logical Properties when applying styles to text content that may invert with reading style. By using logical properties the styles follow the reading direction of the element. i18n support requires this when the user preferences in the browser reverse the reading order.

🎓 Learn about  CSS Logical Properties 🎓 Case Study:  example of inverted form controls

CSS Parts

CSS Parts enable elements to expose DOM elements to consumers that the Shadow DOM would typically encapsulate.


    

Warning: avoid using CSS Parts as they can drastically increase the API surface area of a element and can cause significant costs when updating visual changes in future versions.

CSS Parts give full control to the application developer, but this comes with a significant tradeoff. As the element exposes more internal elements they become part of the public API of the element. Over time increases the difficulty of maintaining the API and making visual changes of the element without causing unexpected visual breaking changes to the consumer.

You can more safely expose elements that are part of the library's public API since each has its own well defined and versioned API. This safely gives more control to the application developer while preventing the element API surface from growing.


    

Part Name Conventions

When naming a part use the name of the custom element without the nve- prefix for API consistency. If a component has many internal part references of the same type use both the generalize element name as well as a semantic name. This allows generalized selectors for theming as well as precise selections when needed.


    

    

Export Parts

Due to higher maintenance complexity, use this API on a per-case basis.

If an element exposes a nve-_ element which is also a nve-_ element, then you can apply an exportparts attribute to expose deeply nested CSS parts.

Example use case, the nve-week component uses a nve-icon-button internally. You can access this via a CSS part.


    

The nve-icon-button internal to nve-week has its own internal nve-icon which it exposes as a part. To access this as a consumer, explicitly add a exportparts to the nve-icon-button and expose its inner nve-icon to the public API surface of `nve-week.


    

Use CSS export parts for advanced theming of nested shadow root elements.

message

Responsive

Elements should be responsive to support a wide variety of use cases. While not all apps are responsive, elements should be responsive to their parent element. This ensures that the element properly renders in any context, regardless if the element is in a datagrid, dashboard or article content. Leverage APIs like ResizeObserver and in the future Container Queries to achieve this.

Performance & Imports

You can extract and import component specific styles from a separate CSS file.


    

Components should not import theme files or text/layout utilities. These stylesheets target global application level styles. Imports cause the styles to be inlined at runtime and create severe performance penalties to consumers of the component.

Don't: