0

In my Astro app I need to pass a variable from the server (frontmatter) to the client.

Like the documentation describe there are two options.

  • use data-attribute
  • use defineVars

As far as I can see now, I can't use both of them?

I need


type Props = {
  uuid: string;
};

const { uuid } = Astro.props;
---

<div class="my-feature" data-uuid={uuid} id="my-feature"></div>

<script is:inline src={import.meta.env.MY_SCRIPT}></script>

<script>
  import { MyFeatureHelper } from '@/scripts/my-helper';

  let myFeature;

  const ref = document.getElementById('my-feature');
  const uuid = ref?.dataset.uuid;
  console.log(uuid);

  myFeature = new MyFeatureHelper(ref as HTMLDivElement, {
    uuid: uuid,
  });

  myFeaturer.build();

</script>

Above is working fine, it's passing correct the variable uuid from the server to the client.

I need a dynamic data-attribute id like:

---
const randomId = Math.random().toString(36).slice(2, 11);
---
<div class="my-feature" data-uuid={uuid} id="my-feature" data-id={randomId}></div>

I need the ref: const ref = document.getElementById('my-feature'); to pass the variables from server to client. So how do I pass data-id attribute and its value now?

I can't use Astro defineVars here, because in that script tag I am also importing a module (import { MyFeatureHelper } from '@/scripts/my-helper';).

Is there a solution for this?

7
  • 1
    I don't get what you are asking. Are you saying, on the client side you can't access the value of data-id in the exact same way, as you are doing for data-uuid...? Commented Dec 19, 2024 at 13:23
  • No. I need the variable randomId to pass to the <script> tag (from server to client) and use it there preferably like: const ref = document.querySelector(`[data-id="${randomId}"]`); Commented Dec 19, 2024 at 14:36
  • Sorry, I can't make sense of what you are saying. "I need the variable randomId to pass to the <script> tag (from server to client) and use it there" - how is this any different, from what you are already doing with the other value? Commented Dec 19, 2024 at 14:51
  • I need a variable ref (for something else) like: const ref = document.getElementById('my-feature');. But this ref should be unique like ref.current in React. So I thought I can do something like: const ref = document.getElementById(my-feature-${randomId});. But that doesn't work because first I have to get the variable randomId. To get randomId, I need it from a data-attribute like const randomId = ref?.dataset.randomId;, but then I can't get element by id because I need the ref for that? Commented Dec 19, 2024 at 14:51
  • "should be unique" - unique in relation to - what? Are you saying, that you will put multiple instances of this component into one page? And now within the script block, you want to access the data-uuid of the "corresponding" div element, that came before the script? Then you should probably rather make use of document.currentScript to get the reference to the current script element, and then navigate the DOM from there, to find the preceding div element ...? Commented Dec 19, 2024 at 15:07

1 Answer 1

1

If I understood you correctly, you're looking for the following:

---
const randomId = Math.random().toString(36).slice(2, 11);
---

<div data-randomId={randomId} id="my-feature"></div>

<script>
  import { MyFeatureHelper } from '@/scripts/my-helper';

  const div = document.getElementById('my-feature');
  console.log(div?.dataset.randomId);
</script>

Note that the JS variable randomId is serialized to a HTML data-attribute (so you cannot use functions or similar objects that don't work with JSON.stringify).

The other thing to note is that if you use a <script> without is:inline in astro, then it will be bundled by vite, so you cannot have dynamic variables that change per request or per page. That's why we serialize that to the HTML and read out from there.

Finally, ref is kinda React terminology. There is no such thing in plain Astro components. And in plain JavaScript, a reference to a DOM node is usually just called div or element or node.

Sign up to request clarification or add additional context in comments.

4 Comments

No, I know already how to pass the variables from server (front matter) to client (to the script tag) with data attributes. That's working fine. Inside this Astro component a Javascript class and script is running and targeting the div like const div = document.getElementById('my-feature');. But this Astro component can be multiple times on a page. Now only the first one is rendered correctly. The second and so on doesn't work. What could be the issue?
that's because the id of an html element needs to be unique on the page. you can either use a class and getElementsByClassName or a web component like in docs.astro.build/en/guides/client-side-scripts/…
thanks with the web component it's working fine. Because now I can use this?.dataset.myId instead of ref?.dataset.myId. Just to understand, what makes using getElementsByClassName different from getElementById in this example?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.