Skip to main content

Contributing new Frameworks

Headless Tree is designed to be framework-agnostic. It provides a React integration as core framework support, but it is possible to create integrations for other frameworks as well. This document outlines how to integrate Headless Tree with custom frameworks, and also how to contribute such integrations back to the project.

The implementation of the React integration can serve as a reference for creating integrations with other frameworks.

Gist of the integration

To create a Headless Tree instance in your framework integration, you need to:

  • Call createTree from @headless-tree/core once and store that reference
  • Call tree.setMounted(true) once when the tree is mounted in the DOM
  • Call tree.rebuildTree() once
  • Call tree.setConfig(prev => ({ ...prev, ...newConfig })) whenever the config changes
  • Call tree.setMounted(false) once when the tree is unmounted from the DOM
  • Maintain a partial state of the tree for all properties that are not explicitly user-managed via their config.state property, and hook that up with:
const [state, setState] = useState<Partial<TreeState<T>>>({});

tree.setConfig(prev => ({
...prev,
state: {
...state,
...userConfig.state,
},
setState: (state) => {
setState(state);
userConfig.setState?.(state);
},
}))

Remapping props

All prop names generated by features are created as React-compliant prop names. You can remap them by implementing a custom feature that overwrites prop-related methods, and rewrites their output in a way that is compatible with your framework. In the following sample, the aria-label prop is remapped to data-label for tree item instances. This can be expanded to every prop if you want.

For a new framework integration, a new custom feature needs to be implemented that remaps all props of props-generating features to the desired prop names of the new framework. Method calls that generate props include:

  • itemInstance.getProps()
  • itemInstance.getCheckboxProps()
  • itemInstance.getRenameInputProps()
  • treeInstance.getSearchInputProps()
  • treeInstance.getContainerProps()

Integration into the Headless Tree monorepo

The following tasks should be done to integrate a new framework into the Headless Tree monorepo:

  • Create a new package in the packages folder, e.g. packages/vue for a Vue integration, and implement and expose the integration hook
  • Write basic unit tests within that package that do a sanity check of the lifecycle and prop renaming
  • Create a new package in the packages folder, e.g. examples/sb-vue, that contains a storybook setup for the new framework integration which includes some sample stories of common use cases.
  • Create a sample app in the examples folder, e.g. examples/vue-app, that can be used to manually test the integration in a real app environment.

Please discuss your integration proposal in the HT Discord or in a GitHub issue before starting the implementation. I (Lukas Bach) or other contributors can also help with individual steps of an integration if needed.