Page objects can be flexible and should reflect the way you write and maintain your tests. For myself, I typically keep my page objects as compact and stateless as possible.
If your pages have a lot of re-usable components, you can put those into smaller classes that encapsulate that functionality independently, then you can use composition to integrate it into any page object that requires it's features. This can reduce the clutter of what can feel like an unwieldy sized page object.
In terms of element management, you could write a container class that accepts a CSS selector or XPath and can get you elements on call. You can also store the selectors as instance fields in your page object to be used on command in your methods to get WebElements exactly when they're needed.
The methods you write for your page object should not reveal the inner WebDriver workings to the test and test writer. If an element can be typed into and read from. It would be better to have two methods perform those explicit actions than it would be to expose the WebDriver layer and return a WebElement or other WebDriver object.
One of the best strengths of the page object model in my opinion is that it creates a total separation between the test layer and WebDriver layer in your code.