Salesforce Lightning Design System for React

repository·master·Indexed 21 days ago

https://github.com/salesforce/design-system-react

A library of accessible, localization-friendly, and presentational React components that implement the Salesforce Lightning Design System (SLDS). The package includes approved SLDS components, a Babel preset (@salesforce/babel-preset-design-system-react) for browser compatibility, and an ESLint plugin (@salesforce/eslint-plugin-slds-react) to align UI components with the SLDS CSS Framework.

Tokens
75.3K
Snippets
187
Records
318
Agent score
74%

What's inside design-system-react

  1. Understand the codebase organization

    master

    The repository is organized into several top-level directories that separate public API components from internal utilities and build scripts:

    • components/: Contains React components.
      • [COMPONENT]/: Public API components. Each contains __tests__ (Mocha/Jest), __examples__ (Storybook/Docs), __docs__ (documentation imports), and a private folder for non-public components.
      • utilities/: Shared components used between other components (not part of the public API).
    • icons/: Legacy inline icons.
    • preset/: The Babel preset @salesforce/babel-preset-design-system-react.
    • scripts/: Build and release tasks.
    • styles/: Temporary location for styles.
    • utilities/: Non-React scripts, including checkProp warnings, DOM, and event helpers (not part of the public API).
  2. Accessibility standards and keyboard navigation

    master

    Components should strive to be accessible and follow SLDS (Salesforce Lightning Design System) patterns. The library aims for WCAG AA compliance.

    Key Accessibility Guidelines:

    • Follow ARIA-1.1 Authoring Practices and the ARIA in HTML reference.
    • Ensure components are keyboard accessible by following the accessibility guidelines for keyboard events on the SLDS website.
    • Use appropriate HTML5 semantic elements to inform ARIA roles.
    • Non-accessible contributions are permitted only if labeled as "prototypes" and an issue is created to address them.
  3. Boolean prop naming conventions

    master

    Boolean props should follow a predictable naming pattern to improve readability:

    • Use prefixes: is, has, or can (e.g., isInline, hasIcon).
    • Use suffixes: -able (e.g., clickable).

    Critical Rule: Never default a boolean prop to true. This ensures consumers do not have to explicitly write propName={false} to disable a feature, which maintains a more natural JSX syntax.

  4. Callback parameter patterns

    master

    To ensure consistency, all callback functions follow a specific parameter pattern:

    • Event Callbacks: Should accept two parameters: the synthetic event (or undefined if no user event triggered it) and a data object containing named key/value pairs related to the event.
      • Pattern: onCallback(event, { key: value })
    • Render Callbacks: Should accept a data object as the second parameter containing all information the render function needs access to.

    Important: Event callback props should not communicate with the parent via return values. Instead, use event.preventDefault() or return false to communicate information back to the component. All data needed to change state should be explicitly provided via the second parameter's data object.

    // Example of an event callback pattern
    this.props.onCallback(event, { extraInfo: true });
  5. How controlled components work in the design system

    master

    The design system prioritizes controlled components. A controlled component does not maintain its own internal state; instead, it renders purely based on the props passed by its parent. This allows the parent application's state engine to manage the component's behavior.

    Key Principles:

    • Prefer Control: New components should always start as controlled. Only add internal state (uncontrolled) if a specific use case requires it.
    • Callback Naming Convention:
      • Prefix callbacks that occur before an event with onRequest (e.g., onRequestClose). This allows the parent to intercept and potentially cancel the action.
      • Prefix callbacks that occur as a result of an event with on (e.g., onClose).
    • Hybrid Support: If a component supports both controlled and uncontrolled modes, the parent can take control simply by passing in a value for the relevant prop.

    Example: Controlled Input

    To implement a controlled input, the parent must manage the state and pass it back to the component via the value prop, while handling updates via an onChange callback.

    class MyForm extends React.Component {
    	constructor(props) {
    		super(props);
    		this.state = { value: 'Hello!' };
    	}
    
    handleChange = (event) => {
    		this.setState({ value: event.target.value });
    	};
    
    render() {
    		return (
    			<input
    				type="text"
    				value={this.state.value}
    				onChange={this.handleChange}
    			/>
    		);
    	}
    }
  6. CSS class name naming conventions

    master

    To maintain a predictable styling structure, follow these rules for className props:

    • Base Component Class: The primary className prop should be applied to the consistent .slds-[COMPONENT] node. Do not apply it to a wrapper container or a child node.
    • Sub-node Classes: Use a className[NODE] prefix for other specific elements within the component (e.g., classNameInput for an input field).
    • Customization Classes: Use descriptive suffixes for other specific nodes (e.g., classNameMenu or classNameContainer).
  7. Component architecture: Stateful vs Stateless

    master

    To maintain a clean and predictable codebase, the library follows a pattern of using a single stateful top-level component paired with multiple stateless sub-components.

    The Pattern:

    • Stateful Top-Level Component: Use a class component to manage the core logic and state for a complex feature. This component acts as the 'smart' container.
    • Stateless Sub-components: Use functional or stateless components for all children. These should be manipulated via props and focus on presentation.

    Examples:

    FeatureStateful ComponentStateless Sub-components
    TreeTreeTreeNode
    Data TableDataTableTableColumn
    Simple UIN/ABadge, Pill, Button, Icon (should generally be stateless)
  8. Handle changes in Dialog component positioning and nubbins

    master

    In version 0.8.21, the positioning logic for Dialog components using 'nubbins' (e.g., Popover, Tooltip, Datepicker, Dropdown) was rewritten for better reliability.

    • Nubbin Alignment: Instead of pointing at the specific corner of a reference trigger (like a Button), the nubbin now calculates offsets to ensure it points to the center of the desired side.
    • Alignment Prop: The align prop (e.g., top left) now designates the location of the nubbin on the Dialog itself, rather than the trigger.
    • Deprecation: The offset prop for Dropdown and Popover is deprecated because manual positional offsets are now considered unreliable due to the new logic.
    • Action Required: Any Dialog component using an offset prop may need manual readjustment.
  9. Mapping SLDS patterns to Design System React props

    master

    When converting Salesforce Lightning Design System (SLDS) patterns to Design System React components, follow these prop conventions to ensure consistent API design:

    • variant: Use for significant structural, markup, or UX pattern changes that are mutually exclusive (e.g., a button that can be either 'primary' or 'destructive'). Do not use event callbacks to imply markup changes (e.g., adding onClick should not change a <span> into an <a>).
    • theme: Use for single className changes that are mutually exclusive, typically representing states like warning, error, offline, or success.
    • Modifiers and States: If multiple modifiers or states can exist simultaneously, they should be implemented as independent props so that any combination is possible.
    • Controlled vs Uncontrolled State: For components like dialogs and menus, the isOpen prop should allow the component to be controlled by a parent, but it must also support internal state management if the value is undefined.
    • Conditional Rendering: Unlike SLDS which often uses CSS to hide elements, Design System React components should not render hidden elements (e.g., do not render menu items, dialogs, or accordion panels if they are not active).
  10. Use fixed headers in DataTable

    master
    Starting in version 0.9.2, the DataTable component supports fixed headers, allowing table headings to remain visible while the table scrolls vertically. In version 0.9.3, default event listeners for window resizing were added to truncate horizontal cells, mimicking the behavior of the Salesforce Platform.
  11. Managing component IDs and accessibility

    master

    To ensure accessibility and prevent DOM collisions, all id attributes must be unique to the page.

    • Top-level components: Should accept an id prop. If not provided, a shortid should be generated by default. This allows developers to set deterministic IDs for testing.
    • Sub-component IDs: Should be constructed by concatenating the component's base id with specific sub-component identifiers to ensure uniqueness (e.g., `tab-panel-${props.componentId}-${props.panelId}`).
  12. Naming conventions for event callback props

    master

    The library follows specific naming conventions for callback functions to distinguish between pre-state-change and post-state-change events:

    • onRequest[ACTION]: Used for pre-state-change events. These callbacks are called before the state change occurs and are intended to allow the parent to validate the state or prevent the change (e.g., onRequestRemove on a Pill is called before the Pill is actually removed).
    • on[EVENT]: Used for post-state-change or post-user-action events. This follows standard React convention and indicates the event or state change has already occurred (e.g., onRemove is called after the Pill is removed).
    • onRender[nodeOrComponentName]: Used for render props. These are callback functions that occur during render and provide the data necessary for the render function (e.g., an options object).