1

I want to dynamically set the max-height of an element based on the number of children it has.

In my component, I am setting a custom property using:

document.documentElement.style.setProperty('--children-count', Children.count(props.children));

and in my css, I use it like this:

&.active {
        .buttonGroup {
            max-height: calc(var(--children-count) * 30px);
        }
    }

This works fine if I am only using it once. However, once I start loading multiple instances of the component with different number children, the --children-count gets overwritten and all the preceding components styles get changed.

How do I go around this?

2
  • You have multiple components competing for them same element. Why? Do you want the sum of the number of children of all elements? Commented Feb 6, 2023 at 2:10
  • Right, that seems to be the problem. I wanted the sum of the children purely because transitions only work with max-height, and if you put a higher value that there is, the animation takes longer than it should Commented Feb 6, 2023 at 2:25

2 Answers 2

0

The issue is most probably because you change the value of the --children-count CSS variable on the top documentElement, therefore affecting ALL your components in the document.

If you want 1 value per Component then simply apply it on an Element of said Component, see e.g. How to apply CSS variable on dynamic CSS class in dynamic component

If you use styled-components, you can also use style adaptation based on props (instead of CSS variables).

Sign up to request clarification or add additional context in comments.

Comments

0

If you need to sync common data between multiple components, pull state upwards! In this case, into a context (unless if you want to manage it with props).

Here's a codesanbox: https://codesandbox.io/s/nervous-lalande-wjpdgb

The key parts of it are the Context Provider which will handle the shared state

function ChildCounterContextProvider({ children }) {
  const [count, setCount] = useState(0);
  const value = useMemo(() => ({ count, setCount }), [count])

  useEffect(() => {
    // Handle changes to number of children here
    document.documentElement.style.setProperty('--children-count', count);
  }, [count]);

  return <ChildCounterContext.Provider value={value}>
    {children}
  </ChildCounterContext.Provider>
}

...and the context consumer, which will write to it.

const useChildCounter = () => useContext(ChildCounterContext);
function MyComponentWithChildren({ children }) {
  const childrenCount = React.Children.count(children);
  const childCounter = useChildCounter();
  useEffect(() => {
    // Add when enters
    childCounter.setCount(n => n+childrenCount);
    // Deduct when exits
    return () => childCounter.setCount(n => n-childrenCount);
  }, [childrenCount, childCounter]);

  return <p>I have {childrenCount} children out of {childCounter.count}</p>
}

The effects will make sure the counts is always in sync.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.