I am currently developing a UI Library using React, Tailwind, HeadlessUI and Storybook. Once I finished the components, and made sure that they worked in Storybook and on a react dev server, I built them and packaged them into a private npm package.
Most of them work fine when I import them in a test project using the created package, but some don't.
All of the not-working components share one thing in common: Importing something from @headlessui/react
.
(The working components don't import anything from headlessui)
When I try using these components in my test project, they all throw the same error:
(Here I chose the component 'Select' as an example)
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check the render method of 'Select'.
The error doesn't really make sense, because those components are exported from my library and imported into my test project exactly the same as the components that work. I even checked that by using a simple console.log
on all components. It came out the same.
Here is how they are imported and exported:
// imported into test project:
import { Select, Form, Dropdown, /* ... */ } from "@my-package";
//exported from the library in index.js:
// ...
import Select from "./components/Select";
export { Select, /* ... */ };
Because I am sure that I imported them correctly into my test project, i am certain that it must have something to do with the build or HeadlessUI.
For building I am using babel.
Although babel never threw errors while building, I figured that I'd still post the confs here.
My build script: "build": "cross-env BABEL_ENV=production babel src -d dist"
My .babelrc:
{
"presets": [
[
"react-app",
{
"absoluteRuntime": false
}
]
],
"plugins": ["babel-plugin-react-css-modules"]
}
Here is some of the non-built and built code from the component 'Select':
// Select.jsx
import React, { Fragment, useState } from "react";
import { Listbox, Transition } from "@headlessui/react";
import { CheckIcon, SelectorIcon } from "@heroicons/react/solid";
import PropTypes from "prop-types";
function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}
export default function Select({
//...
}) {
const selects = options;
let selectedOption;
let i = 0;
selects.map((select) => {
if (select.default) {
selectedOption = selects[i];
return true;
}
i++;
return false;
});
const [selected, setSelected] = useState(selectedOption);
return (
<div className={className}>
<Listbox value={selected} onChange={setSelected}>
{({ open }) => (
<>
<Listbox.Label className="block text-sm font-medium text-gray-700">
{title}
</Listbox.Label>
<div className="mt-1 relative">
<Listbox.Button
className={` bg-white relative border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-primary/60 focus:border-primary sm:text-sm ${
!length || length === "md"
? "w-72"
: length === "fit"
? "w-full"
: length === "lg"
? "w-96"
: length === "sm" && "w-44"
}`}
>
// ...
// Select.js
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = Select;
exports.getSelected = getSelected;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@headlessui/react");
var _solid = require("@heroicons/react/solid");
function Select(_ref) {
// ...
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_react2.Listbox.Label, {
className: "block text-sm font-medium text-gray-700"
}, title), /*#__PURE__*/_react.default.createElement("div", {
className: "mt-1 relative"
}, /*#__PURE__*/_react.default.createElement(_react2.Listbox.Button, {
className: " bg-white relative border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-primary/60 focus:border-primary sm:text-sm ".concat(!length || length === "md" ? "w-72" : length === "fit" ? "w-full" : length === "lg" ? "w-96" : length === "sm" && "w-44")
}, /*#__PURE__*/_react.default.createElement("span", {
className: "block truncate ".concat(placeholder && !selected ? "text-gray-400" : "text-gray-700")
}, selected ? selected.text : placeholder), /*#__PURE__*/_react.default.createElement("span", {
className: "absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"
}, /*#__PURE__*/_react.default.createElement(_solid.SelectorIcon, {
className: "h-5 w-5 text-gray-400",
"aria-hidden": "true"
}))), // ...
Quick Summary:
- Components that import headlessui don't render/work like intended.
- The fault is probably not the importing/exporting but rather the building or HeadlessUI.
I am not sure what to make of this.
Any help is appreciated, thanks in advance!