Well I can only tell you how I'm trying to handle it.
Basically I have my base class UIElement:
public abstract class UIElement
{
public Vector2 Size;
public Rectangle Bounds;
public Texture2D Texture;
public UIElement Parent;
public List<UIElement> Children;
public bool Focused;
protected bool _handledInput;
public virtual void AddChild(UIElement child)
{
Children.Add(child);
}
public virtual void Update(GameTime gameTime)
{
//first update children of this UIElement
var childHandledInput = false;
foreach(child in children)
{
child.Update()
if(child._handledInput)
childHandledInput = true;
}
this._handledInput = false;
//Only handle input if none of the children have handled the input
//and the mouse clicked inside the bounds
if(!childHandledInput && Mouse.Intersects(this.Bounds) && Mouse.Clicked)
{
Focused = true;
_handledInput = true;
}
if(!Mouse.Intersects(this.Bounds) && Mouse.Clicked)
Focused = false;
}
public virtual void Draw(SpriteBatch batch)
{
//Draw self
batch.Draw(Texture, Bounds.Location, Color.White);
foreach(var child in Children)
child.Draw(batch);
}
}
(You have to add some more logic to the focused stuff for parent, but you get the idea)
And then for a textbox you would do something like this:
public class Textbox : UIElement
{
public string Text;
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
if(Focused)
{
//Handle input for changing the text
}
}
}
Now to use alls this you just start with an Element, e.g. a Window.
var window = new Window();
var textbox = new Textbox();
window.Add(textbox);
//...
window.Update(gameTime);
//...
window.Draw(spriteBatch);
This way all children will be drawn and updated and only one element is Focused at a time.
I find this to be a quite simple approach and it works pretty well for me 
Of course this is really a stripped down and incomplete example. For the UIElement you'll need to handle stuff like parent == null. Also adding events is really nice and handling resizing etc.