How would you implement a line of text with a couple links without having spacing issues?

In my case I want to create a checkbox followed by “I agree to the terms and conditions and such and such” where terms and conditions is clickable (along with some more text in such and such) which fires up a modal dialog. I’ve tried to use a HorizontalLayout and added an empty Checkbox(“”) along with a Span() for “I agree to the” and “and …” text with the Terms and Conditions and any other clickable text as a Button with the theme of ButtonVariant.LUMO_TERTIARY_INLINE. This kind of works but there are big spaces between the buttons and the text. I tried to use Html() but that didn’t do any better. I also tried to remove the spacing from the HorizontalLayout but everything was all compressed together without any spaces.

In other words how does one go about creating something like the this, that is a line of text with one or more links in the line of text to a clickable event?

My first guess would be new NativeLavel(new Text(“lorem”), button, new Text(“ipsum”));

(Ensure that the label is associated with the checkbox using for)

You should definintely use an Anchor rather than a Button for links embedded into text.

I’d go with something like this for the whole shebang:

Span text = new Span("I have agreed to the ");
text.addClassName(LumoUtility.Margin.Left.SMALL);

Anchor linkToTerms = new Anchor("https://vaadin.com", "terms and conditions");
linkToTerms.setTarget("_blank");

Checkbox checkBox = new Checkbox();

NativeLabel lbl = new NativeLabel();
lbl.add(checkBox, text, linkToTerms);

(wrapping the checkbox also inside the NativeLabel makes the entire label, except the link, to work as a click-target for the checkbox, and also gives you accessibility for free)

Anchor doesn’t have a ClickListener API, though, so if you need that it gets a bit trickier. You can apply a general eventlistener to the element, but then you also need to prevent the link from actually navigating, which is doable, but then the whole approach starts to feel a bit tiresome.

So an alternative with a Button would use the TERITARY_INLINE variant, which is specifically intended for making the button look OK as an inline element (in line with text). Then you can’t wrap all the things inside the NativeLabel, though, and the label won’t act as click target for the checkbox, but you can still get good a11y through the setAriaLabelledby method:

        Span text = new Span("I have agreed to the ");
        text.addClassName(LumoUtility.Margin.Left.SMALL);

        Button linkToTerms = new Button("terms and conditions");
        linkToTerms.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
        
        NativeLabel lbl = new NativeLabel();
        lbl.add(text, linkToTerms);
        lbl.setId("termslabel");

        Checkbox checkBox = new Checkbox();
        checkBox.setAriaLabelledBy("termslabel");
        
        add(new Div(checkBox, lbl));

The only thing is that I don’t want to go to a link but rather create a Dialog so I need a click event listener. I’m basically faking a link to a popup window.

What seems to be working, but feels very kludgy to me, is to do: horizontalLayout.setSpacing(false); and then add a margin-left: 5px; to the buttons (which are links).

And Spans

what about my second code snippet?

I unfortunately still had spacing issues. The other issue is that I need to fire up a dialog rather than an external link.

I ended up with:

add(new Checkbox(“”), marginHack(new Span("I agree to the “)), marginHack(termsAndConditionsButton), marginHack(new Span(” and ")), marginHack(anotherLinkButton), marginHack(new Span(…)), …);

private static Component marginHack(Component component) {
component.getElement().getStyle().set(“margin-left”, “5px”);
return component;
}

Which could be done with addClassName() I just did it in the code for now.

It’s not perfect but it’s close enough that it’s very hard to see the difference in spacing.

That being said if the screen/panel is shrunk than it fails pretty badly and looks horrible. But I can’t seem to find another solution where I can essentially have a string of html with some way to hook a mouse click event on the even a part of the text.

Not sure I understand the problem with my Button-based example. It looks like this for me:
image.png

the Button has a clicklistener that opens a Dialog

Or if you need more text and another button

Span text1 = new Span("I agree to the ");
text1.addClassName(LumoUtility.Margin.Left.SMALL);

Button linkToTerms = new Button("terms and conditions");
linkToTerms.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);

Span text2 = new Span(" and to ");

Button someOtherButton = new Button("some other things");
        someOtherButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
        
NativeLabel lbl = new NativeLabel();
lbl.add(text1, linkToTerms, text2, someOtherButton);
lbl.setId("termslabel");

Checkbox checkBox = new Checkbox();
checkBox.setAriaLabelledBy("termslabel");
        
add(new Div(checkBox, lbl));```

image.png

Wraps like this when it runs out of space
image.png

Interesting. I must have made an error in transposing it. You are right it works great and does handle wrapping very well.