Skip to content
+

Rich Tree View - Headless

Create your custom Tree View.

Create a custom plugin

Basic plugin

A custom plugins contains 2 required elements:

  1. A hook that will be executed by the useTreeView hook:

    const useCustomPlugin = ({ params }) => {
      React.useEffect(() => {
        console.log(params.customParam);
      });
    
      return {};
    };
    
  2. A property containing the params used by this topic:

    useCustomPlugin.params = {
      customParam: true,
    };
    

Params default value

Use the applyDefaultValuesToParams property to set a default value to your plugin params:

const useCustomPlugin = ({ params }) => {
  React.useEffect(() => {
    console.log(params.customParam);
  });

  return {};
};

useCustomPlugin.params = { customParam: true };

useCustomPlugin.applyDefaultValuesToParams = ({ params }) => ({
  ...params,
  customParam: params.customParam ?? false,
});

Use elements from another plugin

Your plugin can access the instance methods, the params and the state of any other plugin.

const useCustomPlugin = ({ store }) => {
  const handleSomeAction = () => {
    // Log the id of the items currently expanded
    console.log(store.value.expansion.expandedItems);

    // Check if an item is expanded
    const isExpanded = useSelector(selectorIsItemExpanded, 'some-item-id');
  };
};

Define a plugin state

TODO

Populate the Tree View instance

The Tree View instance is an object accessible in all the plugins and in the Tree Item. It is the main way a plugin can provide features to the rest of the component.

const useCustomPlugin = ({ store }) => {
  const toggleCustomModel = () =>
    store.update((prevState) => ({
      ...prevState,
      customModel: !prevState.customModel,
    }));

  return {
    instance: {
      toggleCustomModel,
    },
  };
};

You can then use this instance method in any other plugin:

const useOtherCustomPlugin = ({ instance }) => {
  const handleSomeAction = () => {
    instance.toggleCustomModel();
  };
};

Emit and receive events

const useCustomPlugin = ({ store }) => {
  const toggleCustomModel = () => {
    const newValue = !selectorCustomModel(store.value);
    store.update((prevState) => ({
      ...prevState,
      customModel: newValue,
    }));
    publishTreeViewEvent(instance, 'toggleCustomModel', { value: newValue });
  };

  return {
    instance: {
      toggleCustomModel,
    },
  };
};

You can then subscribe to this event in any other plugin:

const useOtherCustomPlugin = ({ instance }) => {
  useInstanceEventHandler(instance, 'toggleCustomModel', ({ value }) => {
    console.log('New value of customModel', value);
  });
};

Pass props to your root element

Use the getRootProps property of your returned value to pass props to your root element:

const useCustomPlugin = ({ params }) => {
  return {
    getRootProps: () => ({
      'data-customparam': params.customParam,
    }),
  };
};

Pass elements to the Tree Item

Use the contextValue property in the returned object to pass elements to the Tree Item:

const useCustomPlugin = ({ params }) => {
  return {
    contextValue: () => ({
      customPlugin: { enabled: true },
    }),
  };
};

function useTreeItemState(itemId: string) {
  const {
    customPlugin,
    // ...other elements returned by the context
  } = useTreeViewContext<DefaultTreeViewPluginSignatures>();

  // ...rest of the `useTreeItemState` hook content

  return {
    customPlugin,
    // ...other elements returned by `useTreeItemState`
  };
}

function TreeItemContent() {
  const {
    customPlugin,
    // ...other elements returned by `useTreeItemState`
  } = useTreeItemState(props.itemId);

  // Do something with customPlugin.enabled
}

Plugin typing

The typing of a plugin is defined using its signature. This type contains the following information:

type UseCustomPluginSignature = TreeViewPluginSignature<{
  // The params specific to your plugin before running `applyDefaultValuesToParams`
  params: UseCustomPluginParams;
  // The params specific to your plugins after running `applyDefaultValuesToParams`
  paramsWithDefaults: UseCustomPluginParamsWithDefaults;
  // The methods added to the Tree View instance by your plugin
  instance: UseCustomPluginInstance;
  // The events emitted by your plugin
  events: UseCustomPluginEvents;
  // The states defined by your plugin
  state: UseCustomPluginState;
  // The plugins this plugin needs to work correctly
  dependencies: UseCustomPluginDependantPlugins;
}>;

The most basic plugin would have the following signature:

type UseCustomPluginSignature = TreeViewPluginSignature<{}>;

The plugin built in the sections above would have the following signature:

type UseCustomPluginSignature = TreeViewPluginSignature<{
  params: {
    customParam?: boolean;
    customModel?: boolean;
    defaultCustomModel?: boolean;
  };
  // `customParam` and `defaultCustomModel` have a default value defined in `applyDefaultValuesToParams`
  paramsWithDefaults: {
    customParam: boolean;
    customModel?: boolean;
    defaultCustomModel: boolean;
  };
  instance: { toggleCustomModel: () => void };
  events: {
    toggleCustomModel: {
      params: { value: boolean };
    };
  };
  contextValue: { customPlugin: { enabled: boolean } };
  dependencies: [UseTreeViewExpansionSignature];
}>;

Examples

Log expanded items

Interact with the Tree View to see the expanded items being logged:

Press Enter to start editing