Now that you're familiar with a couple of baseline approaches, let's discuss a few best practices for making these components easier to use and maintain.
When creating your component variations/states as separate components, you'll want to preserve your text overrides if you plan on swapping between them—this way you don't have to re-input the text. To ensure that your text is maintained during this swap, make sure the text layers within each component are renamed to be the same as each other (since by default, the layer name will inherit whatever you initially type into the text box).
You can add a description to each main component in the properties sidebar. These descriptions show up as tool tips on hover in the components panel. This is also a good place to include info about their intended usage to help users pick the right components.
Take the time to setup proper constraints to ensure predictable and intended behavior when components are resized. Since components function the same way as frames, you can add layout grids within your components and even apply constraints to elements that are relative to the grid. They can also be used to help visualize margins or padding within your component.
You can toggle the clip content checkbox in the properties panel to define whether or not elements which extend outside the bounds of the frame are cropped/hidden. This feature can be really useful if you have components with repeated elements that you may want to reveal when resized. For example, the number of rows in a table might vary from use case to use case—with this method you can simply resize the component to reveal the number of rows you need. Make sure you setup constraints for all of the elements within your component first!