The idea is that the component's external API is not the DOM. That also means your data should flow in a certain way.
You don't usually read a component's state from outside (here: the "checked" property).
Instead you define an API where data only flows top-down.
When your checkbox component follows this paradigm, it is "controlled", and if it contains a standard HTML input, that input's "checked" DOM object property is bound to the data passed into the component ("props"). Clicking it won't check it anymore until you add an "onClick" callback an use that from the outside to modify the "checked" prop.
Because "controlled" means you tell React to always force the "checked" DOM property to be the same as the "checked" prop you pass into the component. You do this by assigning to the reflected "checked" HTML attribute in JSX.
When your components only use this "top-down" data flow, they're "pure" in React lingo. Because they look like pure functions: props => DOM. The machinery behind the scenes means they're not actually that.
But if you don't use internal state (e.g. useState hook) or global stores, they behave pretty much like this.
And it can make some things easier.
For example:
HTMLInputElement.checked can be true without a "checked" attribute being in the markup.
If you want to have som text next to it that says "checked / not checked" you have to wire stuff.
If you have a "controlled" React checkbox, you have a tree: the checked state lives above both the info text and the checkbox.
You don't need to read from the checkbox to update the text. You feed both with a boolean and both can be "pure" components. The checkbox gets a "onClick" callback and it's checked state is no longer internal, it's "controlled".
The wiring you have to do instead of the regular DOM events (which would read the input's state) is now to use your "onClick" callback to toggle your boolean.
Internally, in the component, you do whatever you need to read and write to the DOM. But usually that just means "what markup do I return".
Input elements and reflected attributes such as "checked" are already a relatively complex case.
And, you can escape the recommended top-down data flow by many means (refs, context, accessing centralized "stores" from within the component...), but that's often where it gets ugly. But you need to do it often when your app gets bigger (centralized data stores), or when you implement things like UI libraries (refs).